cclasses.pas 47 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806
  1. {
  2. $Id$
  3. Copyright (c) 1998-2000 by Florian Klaempfl and Peter Vreman
  4. This module provides some basic classes
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. unit cclasses;
  19. {$i defines.inc}
  20. interface
  21. uses
  22. cutils,cstreams;
  23. {********************************************
  24. TMemDebug
  25. ********************************************}
  26. type
  27. tmemdebug = class
  28. private
  29. startmem : integer;
  30. infostr : string[40];
  31. public
  32. constructor Create(const s:string);
  33. destructor Destroy;override;
  34. procedure show;
  35. end;
  36. {********************************************
  37. TLinkedList
  38. ********************************************}
  39. type
  40. TLinkedListItem = class
  41. public
  42. Previous,
  43. Next : TLinkedListItem;
  44. Constructor Create;
  45. Destructor Destroy;override;
  46. Function GetCopy:TLinkedListItem;virtual;
  47. end;
  48. TLinkedListItemClass = class of TLinkedListItem;
  49. TLinkedList = class
  50. private
  51. FCount : integer;
  52. FFirst,
  53. FLast : TLinkedListItem;
  54. public
  55. constructor Create;
  56. destructor Destroy;override;
  57. { true when the List is empty }
  58. function Empty:boolean;
  59. { deletes all Items }
  60. procedure Clear;
  61. { inserts an Item }
  62. procedure Insert(Item:TLinkedListItem);
  63. { concats an Item }
  64. procedure Concat(Item:TLinkedListItem);
  65. { deletes an Item }
  66. procedure Remove(Item:TLinkedListItem);
  67. { Gets First Item }
  68. function GetFirst:TLinkedListItem;
  69. { Gets last Item }
  70. function GetLast:TLinkedListItem;
  71. { inserts another List at the begin and make this List empty }
  72. procedure insertList(p : TLinkedList);
  73. { concats another List at the end and make this List empty }
  74. procedure concatList(p : TLinkedList);
  75. { concats another List at the end and makes a copy }
  76. procedure insertListcopy(p : TLinkedList);
  77. { concats another List at the end and makes a copy }
  78. procedure concatListcopy(p : TLinkedList);
  79. property First:TLinkedListItem read FFirst;
  80. property Last:TLinkedListItem read FLast;
  81. property Count:Integer read FCount;
  82. end;
  83. {********************************************
  84. TStringList
  85. ********************************************}
  86. { string containerItem }
  87. TStringListItem = class(TLinkedListItem)
  88. FPStr : PString;
  89. public
  90. constructor Create(const s:string);
  91. destructor Destroy;override;
  92. function GetCopy:TLinkedListItem;override;
  93. function Str:string;
  94. end;
  95. { string container }
  96. TStringList = class(TLinkedList)
  97. private
  98. FDoubles : boolean; { if this is set to true, doubles are allowed }
  99. public
  100. constructor Create;
  101. constructor Create_No_Double;
  102. { inserts an Item }
  103. procedure Insert(const s:string);
  104. { concats an Item }
  105. procedure Concat(const s:string);
  106. { deletes an Item }
  107. procedure Remove(const s:string);
  108. { Gets First Item }
  109. function GetFirst:string;
  110. { Gets last Item }
  111. function GetLast:string;
  112. { true if string is in the container }
  113. function Find(const s:string):TStringListItem;
  114. { inserts an item }
  115. procedure InsertItem(item:TStringListItem);
  116. { concats an item }
  117. procedure ConcatItem(item:TStringListItem);
  118. property Doubles:boolean read FDoubles write FDoubles;
  119. end;
  120. {********************************************
  121. Dictionary
  122. ********************************************}
  123. const
  124. { the real size will be [0..hasharray-1] ! }
  125. hasharraysize = 512;
  126. type
  127. { namedindexobect for use with dictionary and indexarray }
  128. TNamedIndexItem=class
  129. private
  130. { indexarray }
  131. FIndexNr : integer;
  132. FIndexNext : TNamedIndexItem;
  133. { dictionary }
  134. FLeft,
  135. FRight : TNamedIndexItem;
  136. FSpeedValue : cardinal;
  137. { singleList }
  138. FListNext : TNamedIndexItem;
  139. protected
  140. function GetName:string;virtual;
  141. procedure SetName(const n:string);virtual;
  142. public
  143. FName : Pstring;
  144. constructor Create;
  145. constructor CreateName(const n:string);
  146. destructor Destroy;override;
  147. property IndexNr:integer read FIndexNr write FIndexNr;
  148. property IndexNext:TNamedIndexItem read FIndexNext write FIndexNext;
  149. property Name:string read GetName write SetName;
  150. property SpeedValue:cardinal read FSpeedValue;
  151. property ListNext:TNamedIndexItem read FListNext;
  152. property Left:TNamedIndexItem read FLeft write FLeft;
  153. property Right:TNamedIndexItem read FRight write FRight;
  154. end;
  155. Pdictionaryhasharray=^Tdictionaryhasharray;
  156. Tdictionaryhasharray=array[0..hasharraysize-1] of TNamedIndexItem;
  157. TnamedIndexCallback = procedure(p:TNamedIndexItem) of object;
  158. TnamedIndexStaticCallback = procedure(p:TNamedIndexItem);
  159. Tdictionary=class
  160. private
  161. FRoot : TNamedIndexItem;
  162. FHashArray : Pdictionaryhasharray;
  163. procedure cleartree(obj:TNamedIndexItem);
  164. function insertNode(NewNode:TNamedIndexItem;var currNode:TNamedIndexItem):TNamedIndexItem;
  165. procedure inserttree(currtree,currroot:TNamedIndexItem);
  166. public
  167. noclear : boolean;
  168. replace_existing : boolean;
  169. delete_doubles : boolean;
  170. constructor Create;
  171. destructor Destroy;override;
  172. procedure usehash;
  173. procedure clear;
  174. function delete(const s:string):TNamedIndexItem;
  175. function empty:boolean;
  176. procedure foreach(proc2call:TNamedIndexcallback);
  177. procedure foreach_static(proc2call:TNamedIndexStaticCallback);
  178. function insert(obj:TNamedIndexItem):TNamedIndexItem;
  179. function rename(const olds,News : string):TNamedIndexItem;
  180. function search(const s:string):TNamedIndexItem;
  181. function speedsearch(const s:string;SpeedValue:cardinal):TNamedIndexItem;
  182. property Items[const s:string]:TNamedIndexItem read Search;default;
  183. end;
  184. tsingleList=class
  185. First,
  186. last : TNamedIndexItem;
  187. constructor Create;
  188. procedure reset;
  189. procedure clear;
  190. procedure insert(p:TNamedIndexItem);
  191. end;
  192. tindexobjectarray=array[1..16000] of TNamedIndexItem;
  193. pnamedindexobjectarray=^tindexobjectarray;
  194. tindexarray=class
  195. noclear : boolean;
  196. First : TNamedIndexItem;
  197. count : integer;
  198. constructor Create(Agrowsize:integer);
  199. destructor destroy;override;
  200. procedure clear;
  201. procedure foreach(proc2call : Tnamedindexcallback);
  202. procedure foreach_static(proc2call : Tnamedindexstaticcallback);
  203. procedure deleteindex(p:TNamedIndexItem);
  204. procedure delete(var p:TNamedIndexItem);
  205. procedure insert(p:TNamedIndexItem);
  206. function search(nr:integer):TNamedIndexItem;
  207. private
  208. growsize,
  209. size : integer;
  210. data : pnamedindexobjectarray;
  211. procedure grow(gsize:integer);
  212. end;
  213. {********************************************
  214. DynamicArray
  215. ********************************************}
  216. const
  217. dynamicblockbasesize = 12;
  218. type
  219. pdynamicblock = ^tdynamicblock;
  220. tdynamicblock = record
  221. pos,
  222. used : integer;
  223. Next : pdynamicblock;
  224. data : array[0..high(integer)-20] of byte;
  225. end;
  226. tdynamicarray = class
  227. private
  228. FPosn : integer;
  229. FPosnblock : pdynamicblock;
  230. FBlocksize : integer;
  231. FFirstblock,
  232. FLastblock : pdynamicblock;
  233. procedure grow;
  234. public
  235. constructor Create(Ablocksize:integer);
  236. destructor Destroy;override;
  237. function size:integer;
  238. procedure align(i:integer);
  239. procedure seek(i:integer);
  240. function read(var d;len:integer):integer;
  241. procedure write(const d;len:integer);
  242. procedure writestr(const s:string);
  243. procedure readstream(f:TCStream;maxlen:longint);
  244. procedure writestream(f:TCStream);
  245. property BlockSize : integer read FBlocksize;
  246. property FirstBlock : PDynamicBlock read FFirstBlock;
  247. end;
  248. { Speed/Hash value }
  249. Function GetSpeedValue(Const s:String):cardinal;
  250. implementation
  251. {*****************************************************************************
  252. GetSpeedValue
  253. *****************************************************************************}
  254. {$ifdef ver1_0}
  255. {$R-}
  256. {$endif}
  257. var
  258. Crc32Tbl : array[0..255] of cardinal;
  259. procedure MakeCRC32Tbl;
  260. var
  261. crc : cardinal;
  262. i,n : integer;
  263. begin
  264. for i:=0 to 255 do
  265. begin
  266. crc:=i;
  267. for n:=1 to 8 do
  268. if odd(longint(crc)) then
  269. crc:=cardinal(crc shr 1) xor cardinal($edb88320)
  270. else
  271. crc:=cardinal(crc shr 1);
  272. Crc32Tbl[i]:=crc;
  273. end;
  274. end;
  275. Function GetSpeedValue(Const s:String):cardinal;
  276. var
  277. i : integer;
  278. InitCrc : cardinal;
  279. begin
  280. if Crc32Tbl[1]=0 then
  281. MakeCrc32Tbl;
  282. InitCrc:=cardinal($ffffffff);
  283. for i:=1 to Length(s) do
  284. InitCrc:=Crc32Tbl[byte(InitCrc) xor ord(s[i])] xor (InitCrc shr 8);
  285. GetSpeedValue:=InitCrc;
  286. end;
  287. {*****************************************************************************
  288. Memory debug
  289. *****************************************************************************}
  290. constructor tmemdebug.create(const s:string);
  291. begin
  292. infostr:=s;
  293. {$ifdef Delphi}
  294. startmem:=0;
  295. {$else}
  296. startmem:=memavail;
  297. {$endif Delphi}
  298. end;
  299. destructor tmemdebug.destroy;
  300. begin
  301. show;
  302. end;
  303. procedure tmemdebug.show;
  304. {$ifndef Delphi}
  305. var
  306. l : integer;
  307. {$endif}
  308. begin
  309. {$ifndef Delphi}
  310. write('memory [',infostr,'] ');
  311. l:=memavail;
  312. if l>startmem then
  313. writeln(l-startmem,' released')
  314. else
  315. writeln(startmem-l,' allocated');
  316. {$endif Delphi}
  317. end;
  318. {*****************************************************************************
  319. Stack
  320. *****************************************************************************}
  321. {$ifdef fixLeaksOnError}
  322. constructor TStack.init;
  323. begin
  324. head := nil;
  325. end;
  326. procedure TStack.push(p: pointer);
  327. var s: PStackItem;
  328. begin
  329. New(s);
  330. s^.data := p;
  331. s^.Next := head;
  332. head := s;
  333. end;
  334. function TStack.pop: pointer;
  335. var s: PStackItem;
  336. begin
  337. pop := top;
  338. if assigned(head) then
  339. begin
  340. s := head^.Next;
  341. dispose(head);
  342. head := s;
  343. end
  344. end;
  345. function TStack.top: pointer;
  346. begin
  347. if not isEmpty then
  348. top := head^.data
  349. else top := NIL;
  350. end;
  351. function TStack.isEmpty: boolean;
  352. begin
  353. isEmpty := head = nil;
  354. end;
  355. destructor TStack.done;
  356. var temp: PStackItem;
  357. begin
  358. while head <> nil do
  359. begin
  360. temp := head^.Next;
  361. dispose(head);
  362. head := temp;
  363. end;
  364. end;
  365. {$endif fixLeaksOnError}
  366. {****************************************************************************
  367. TLinkedListItem
  368. ****************************************************************************}
  369. constructor TLinkedListItem.Create;
  370. begin
  371. Previous:=nil;
  372. Next:=nil;
  373. end;
  374. destructor TLinkedListItem.Destroy;
  375. begin
  376. end;
  377. function TLinkedListItem.GetCopy:TLinkedListItem;
  378. var
  379. p : TLinkedListItem;
  380. l : integer;
  381. begin
  382. p:=TLinkedListItemClass(ClassType).Create;
  383. l:=InstanceSize;
  384. Move(pointer(self)^,pointer(p)^,l);
  385. Result:=p;
  386. end;
  387. {****************************************************************************
  388. TLinkedList
  389. ****************************************************************************}
  390. constructor TLinkedList.Create;
  391. begin
  392. FFirst:=nil;
  393. Flast:=nil;
  394. FCount:=0;
  395. end;
  396. destructor TLinkedList.destroy;
  397. begin
  398. Clear;
  399. end;
  400. function TLinkedList.empty:boolean;
  401. begin
  402. Empty:=(FFirst=nil);
  403. end;
  404. procedure TLinkedList.Insert(Item:TLinkedListItem);
  405. begin
  406. if FFirst=nil then
  407. begin
  408. FLast:=Item;
  409. Item.Previous:=nil;
  410. Item.Next:=nil;
  411. end
  412. else
  413. begin
  414. FFirst.Previous:=Item;
  415. Item.Previous:=nil;
  416. Item.Next:=FFirst;
  417. end;
  418. FFirst:=Item;
  419. inc(FCount);
  420. end;
  421. procedure TLinkedList.Concat(Item:TLinkedListItem);
  422. begin
  423. if FFirst=nil then
  424. begin
  425. FFirst:=Item;
  426. Item.Previous:=nil;
  427. Item.Next:=nil;
  428. end
  429. else
  430. begin
  431. Flast.Next:=Item;
  432. Item.Previous:=Flast;
  433. Item.Next:=nil;
  434. end;
  435. Flast:=Item;
  436. inc(FCount);
  437. end;
  438. procedure TLinkedList.remove(Item:TLinkedListItem);
  439. begin
  440. if Item=nil then
  441. exit;
  442. if (FFirst=Item) and (Flast=Item) then
  443. begin
  444. FFirst:=nil;
  445. Flast:=nil;
  446. end
  447. else if FFirst=Item then
  448. begin
  449. FFirst:=Item.Next;
  450. if assigned(FFirst) then
  451. FFirst.Previous:=nil;
  452. end
  453. else if Flast=Item then
  454. begin
  455. Flast:=Flast.Previous;
  456. if assigned(Flast) then
  457. Flast.Next:=nil;
  458. end
  459. else
  460. begin
  461. Item.Previous.Next:=Item.Next;
  462. Item.Next.Previous:=Item.Previous;
  463. end;
  464. Item.Next:=nil;
  465. Item.Previous:=nil;
  466. dec(FCount);
  467. end;
  468. procedure TLinkedList.clear;
  469. var
  470. NewNode : TLinkedListItem;
  471. begin
  472. NewNode:=FFirst;
  473. while assigned(NewNode) do
  474. begin
  475. FFirst:=NewNode.Next;
  476. NewNode.Free;
  477. NewNode:=FFirst;
  478. end;
  479. FLast:=nil;
  480. FFirst:=nil;
  481. FCount:=0;
  482. end;
  483. function TLinkedList.GetFirst:TLinkedListItem;
  484. begin
  485. if FFirst=nil then
  486. GetFirst:=nil
  487. else
  488. begin
  489. GetFirst:=FFirst;
  490. if FFirst=FLast then
  491. FLast:=nil;
  492. FFirst:=FFirst.Next;
  493. dec(FCount);
  494. end;
  495. end;
  496. function TLinkedList.GetLast:TLinkedListItem;
  497. begin
  498. if FLast=nil then
  499. Getlast:=nil
  500. else
  501. begin
  502. Getlast:=FLast;
  503. if FLast=FFirst then
  504. FFirst:=nil;
  505. FLast:=FLast.Previous;
  506. dec(FCount);
  507. end;
  508. end;
  509. procedure TLinkedList.insertList(p : TLinkedList);
  510. begin
  511. { empty List ? }
  512. if (p.FFirst=nil) then
  513. exit;
  514. p.Flast.Next:=FFirst;
  515. { we have a double Linked List }
  516. if assigned(FFirst) then
  517. FFirst.Previous:=p.Flast;
  518. FFirst:=p.FFirst;
  519. if (FLast=nil) then
  520. Flast:=p.Flast;
  521. { p becomes empty }
  522. p.FFirst:=nil;
  523. p.Flast:=nil;
  524. end;
  525. procedure TLinkedList.concatList(p : TLinkedList);
  526. begin
  527. if (p.FFirst=nil) then
  528. exit;
  529. if FFirst=nil then
  530. FFirst:=p.FFirst
  531. else
  532. begin
  533. FLast.Next:=p.FFirst;
  534. p.FFirst.Previous:=Flast;
  535. end;
  536. Flast:=p.Flast;
  537. { make p empty }
  538. p.Flast:=nil;
  539. p.FFirst:=nil;
  540. end;
  541. procedure TLinkedList.insertListcopy(p : TLinkedList);
  542. var
  543. NewNode,NewNode2 : TLinkedListItem;
  544. begin
  545. NewNode:=p.First;
  546. while assigned(NewNode) do
  547. begin
  548. NewNode2:=NewNode.Getcopy;
  549. if assigned(NewNode2) then
  550. Insert(NewNode2);
  551. NewNode:=NewNode.Next;
  552. end;
  553. end;
  554. procedure TLinkedList.concatListcopy(p : TLinkedList);
  555. var
  556. NewNode,NewNode2 : TLinkedListItem;
  557. begin
  558. NewNode:=p.First;
  559. while assigned(NewNode) do
  560. begin
  561. NewNode2:=NewNode.Getcopy;
  562. if assigned(NewNode2) then
  563. Concat(NewNode2);
  564. NewNode:=NewNode.Next;
  565. end;
  566. end;
  567. {****************************************************************************
  568. TStringListItem
  569. ****************************************************************************}
  570. constructor TStringListItem.Create(const s:string);
  571. begin
  572. inherited Create;
  573. FPStr:=stringdup(s);
  574. end;
  575. destructor TStringListItem.Destroy;
  576. begin
  577. stringdispose(FPStr);
  578. end;
  579. function TStringListItem.Str:string;
  580. begin
  581. Str:=FPStr^;
  582. end;
  583. function TStringListItem.GetCopy:TLinkedListItem;
  584. begin
  585. Result:=(inherited GetCopy);
  586. TStringListItem(Result).FPStr:=stringdup(FPstr^);
  587. end;
  588. {****************************************************************************
  589. TSTRINGList
  590. ****************************************************************************}
  591. constructor tstringList.Create;
  592. begin
  593. inherited Create;
  594. FDoubles:=true;
  595. end;
  596. constructor tstringList.Create_no_double;
  597. begin
  598. inherited Create;
  599. FDoubles:=false;
  600. end;
  601. procedure tstringList.insert(const s : string);
  602. begin
  603. if (s='') or
  604. ((not FDoubles) and (find(s)<>nil)) then
  605. exit;
  606. inherited insert(tstringListItem.create(s));
  607. end;
  608. procedure tstringList.concat(const s : string);
  609. begin
  610. if (s='') or
  611. ((not FDoubles) and (find(s)<>nil)) then
  612. exit;
  613. inherited concat(tstringListItem.create(s));
  614. end;
  615. procedure tstringList.remove(const s : string);
  616. var
  617. p : tstringListItem;
  618. begin
  619. if s='' then
  620. exit;
  621. p:=find(s);
  622. if assigned(p) then
  623. begin
  624. inherited Remove(p);
  625. p.Free;
  626. end;
  627. end;
  628. function tstringList.GetFirst : string;
  629. var
  630. p : tstringListItem;
  631. begin
  632. p:=tstringListItem(inherited GetFirst);
  633. if p=nil then
  634. GetFirst:=''
  635. else
  636. begin
  637. GetFirst:=p.FPStr^;
  638. p.free;
  639. end;
  640. end;
  641. function tstringList.Getlast : string;
  642. var
  643. p : tstringListItem;
  644. begin
  645. p:=tstringListItem(inherited Getlast);
  646. if p=nil then
  647. Getlast:=''
  648. else
  649. begin
  650. Getlast:=p.FPStr^;
  651. p.free;
  652. end;
  653. end;
  654. function tstringList.find(const s:string):TstringListItem;
  655. var
  656. NewNode : tstringListItem;
  657. begin
  658. find:=nil;
  659. if s='' then
  660. exit;
  661. NewNode:=tstringListItem(FFirst);
  662. while assigned(NewNode) do
  663. begin
  664. if NewNode.FPStr^=s then
  665. begin
  666. find:=NewNode;
  667. exit;
  668. end;
  669. NewNode:=tstringListItem(NewNode.Next);
  670. end;
  671. end;
  672. procedure TStringList.InsertItem(item:TStringListItem);
  673. begin
  674. inherited Insert(item);
  675. end;
  676. procedure TStringList.ConcatItem(item:TStringListItem);
  677. begin
  678. inherited Concat(item);
  679. end;
  680. {****************************************************************************
  681. TNamedIndexItem
  682. ****************************************************************************}
  683. constructor TNamedIndexItem.Create;
  684. begin
  685. { index }
  686. Findexnr:=-1;
  687. FindexNext:=nil;
  688. { dictionary }
  689. Fleft:=nil;
  690. Fright:=nil;
  691. FName:=nil;
  692. Fspeedvalue:=cardinal($ffffffff);
  693. { List }
  694. FListNext:=nil;
  695. end;
  696. constructor TNamedIndexItem.Createname(const n:string);
  697. begin
  698. { index }
  699. Findexnr:=-1;
  700. FindexNext:=nil;
  701. { dictionary }
  702. Fleft:=nil;
  703. Fright:=nil;
  704. Fspeedvalue:=cardinal($ffffffff);
  705. FName:=stringdup(n);
  706. { List }
  707. FListNext:=nil;
  708. end;
  709. destructor TNamedIndexItem.destroy;
  710. begin
  711. stringdispose(FName);
  712. end;
  713. procedure TNamedIndexItem.setname(const n:string);
  714. begin
  715. if speedvalue=cardinal($ffffffff) then
  716. begin
  717. if assigned(FName) then
  718. stringdispose(FName);
  719. FName:=stringdup(n);
  720. end;
  721. end;
  722. function TNamedIndexItem.GetName:string;
  723. begin
  724. if assigned(FName) then
  725. Getname:=FName^
  726. else
  727. Getname:='';
  728. end;
  729. {****************************************************************************
  730. TDICTIONARY
  731. ****************************************************************************}
  732. constructor Tdictionary.Create;
  733. begin
  734. FRoot:=nil;
  735. FHashArray:=nil;
  736. noclear:=false;
  737. replace_existing:=false;
  738. delete_doubles:=false;
  739. end;
  740. procedure Tdictionary.usehash;
  741. begin
  742. if not(assigned(FRoot)) and
  743. not(assigned(FHashArray)) then
  744. begin
  745. New(FHashArray);
  746. fillchar(FHashArray^,sizeof(FHashArray^),0);
  747. end;
  748. end;
  749. function counttree(p: tnamedindexitem): longint;
  750. begin
  751. if not assigned(p) then
  752. exit(0);
  753. result := 1;
  754. inc(result,counttree(p.fleft));
  755. inc(result,counttree(p.fright));
  756. end;
  757. destructor Tdictionary.destroy;
  758. {$ifdef hashdebug}
  759. var
  760. i, unused, slots_with_col, collissions, treecount, maxcol: longint;
  761. {$endif hashdebug}
  762. begin
  763. if not noclear then
  764. clear;
  765. if assigned(FHashArray) then
  766. begin
  767. {$ifdef hashdebug}
  768. unused := 0;
  769. collissions := 0;
  770. maxcol := 0;
  771. slots_with_col := 0;
  772. for i := low(fhasharray^) to high(fhasharray^) do
  773. if assigned(fhasharray^[i]) then
  774. begin
  775. treecount := counttree(fhasharray^[i]);
  776. inc(collissions,sqr(treecount-1));
  777. if treecount > maxcol then
  778. maxcol := treecount;
  779. inc(slots_with_col,ord(treecount>1));
  780. end
  781. else
  782. inc(unused);
  783. writeln('Slots unused: ',unused,' out of ',hasharraysize,
  784. ' (',slots_with_col,' with >1 items)');
  785. writeln('Mean number of collissions: ',
  786. (sqrt(collissions / extended(hasharraysize-1))):0:3,' (max: ',maxcol,')');
  787. writeln;
  788. {$endif hashdebug}
  789. dispose(FHashArray);
  790. end;
  791. end;
  792. procedure Tdictionary.cleartree(obj:TNamedIndexItem);
  793. begin
  794. if assigned(obj.Fleft) then
  795. cleartree(obj.FLeft);
  796. if assigned(obj.FRight) then
  797. cleartree(obj.FRight);
  798. obj.free;
  799. obj:=nil;
  800. end;
  801. procedure Tdictionary.clear;
  802. var
  803. w : integer;
  804. begin
  805. if assigned(FRoot) then
  806. cleartree(FRoot);
  807. if assigned(FHashArray) then
  808. for w:= low(FHashArray^) to high(FHashArray^) do
  809. if assigned(FHashArray^[w]) then
  810. cleartree(FHashArray^[w]);
  811. end;
  812. function Tdictionary.delete(const s:string):TNamedIndexItem;
  813. var
  814. p,SpeedValue : cardinal;
  815. n : TNamedIndexItem;
  816. procedure insert_right_bottom(var root,Atree:TNamedIndexItem);
  817. begin
  818. while root.FRight<>nil do
  819. root:=root.FRight;
  820. root.FRight:=Atree;
  821. end;
  822. function delete_from_tree(root:TNamedIndexItem):TNamedIndexItem;
  823. type
  824. leftright=(left,right);
  825. var
  826. lr : leftright;
  827. oldroot : TNamedIndexItem;
  828. begin
  829. oldroot:=nil;
  830. while (root<>nil) and (root.SpeedValue<>SpeedValue) do
  831. begin
  832. oldroot:=root;
  833. if SpeedValue<root.SpeedValue then
  834. begin
  835. root:=root.FRight;
  836. lr:=right;
  837. end
  838. else
  839. begin
  840. root:=root.FLeft;
  841. lr:=left;
  842. end;
  843. end;
  844. while (root<>nil) and (root.FName^<>s) do
  845. begin
  846. oldroot:=root;
  847. if s<root.FName^ then
  848. begin
  849. root:=root.FRight;
  850. lr:=right;
  851. end
  852. else
  853. begin
  854. root:=root.FLeft;
  855. lr:=left;
  856. end;
  857. end;
  858. if root.FLeft<>nil then
  859. begin
  860. { Now the Node pointing to root must point to the left
  861. subtree of root. The right subtree of root must be
  862. connected to the right bottom of the left subtree.}
  863. if lr=left then
  864. oldroot.FLeft:=root.FLeft
  865. else
  866. oldroot.FRight:=root.FLeft;
  867. if root.FRight<>nil then
  868. insert_right_bottom(root.FLeft,root.FRight);
  869. end
  870. else
  871. begin
  872. { There is no left subtree. So we can just replace the Node to
  873. delete with the right subtree.}
  874. if lr=left then
  875. oldroot.FLeft:=root.FRight
  876. else
  877. oldroot.FRight:=root.FRight;
  878. end;
  879. delete_from_tree:=root;
  880. end;
  881. begin
  882. SpeedValue:=GetSpeedValue(s);
  883. n:=FRoot;
  884. if assigned(FHashArray) then
  885. begin
  886. { First, check if the Node to delete directly located under
  887. the hasharray.}
  888. p:=SpeedValue mod hasharraysize;
  889. n:=FHashArray^[p];
  890. if (n<>nil) and (n.SpeedValue=SpeedValue) and
  891. (n.FName^=s) then
  892. begin
  893. { The Node to delete is directly located under the
  894. hasharray. Make the hasharray point to the left
  895. subtree of the Node and place the right subtree on
  896. the right-bottom of the left subtree.}
  897. if n.FLeft<>nil then
  898. begin
  899. FHashArray^[p]:=n.FLeft;
  900. if n.FRight<>nil then
  901. insert_right_bottom(n.FLeft,n.FRight);
  902. end
  903. else
  904. FHashArray^[p]:=n.FRight;
  905. delete:=n;
  906. exit;
  907. end;
  908. end
  909. else
  910. begin
  911. { First check if the Node to delete is the root.}
  912. if (FRoot<>nil) and (n.SpeedValue=SpeedValue) and
  913. (n.FName^=s) then
  914. begin
  915. if n.FLeft<>nil then
  916. begin
  917. FRoot:=n.FLeft;
  918. if n.FRight<>nil then
  919. insert_right_bottom(n.FLeft,n.FRight);
  920. end
  921. else
  922. FRoot:=n.FRight;
  923. delete:=n;
  924. exit;
  925. end;
  926. end;
  927. delete:=delete_from_tree(n);
  928. end;
  929. function Tdictionary.empty:boolean;
  930. var
  931. w : integer;
  932. begin
  933. if assigned(FHashArray) then
  934. begin
  935. empty:=false;
  936. for w:=low(FHashArray^) to high(FHashArray^) do
  937. if assigned(FHashArray^[w]) then
  938. exit;
  939. empty:=true;
  940. end
  941. else
  942. empty:=(FRoot=nil);
  943. end;
  944. procedure Tdictionary.foreach(proc2call:TNamedIndexcallback);
  945. procedure a(p:TNamedIndexItem);
  946. begin
  947. proc2call(p);
  948. if assigned(p.FLeft) then
  949. a(p.FLeft);
  950. if assigned(p.FRight) then
  951. a(p.FRight);
  952. end;
  953. var
  954. i : integer;
  955. begin
  956. if assigned(FHashArray) then
  957. begin
  958. for i:=low(FHashArray^) to high(FHashArray^) do
  959. if assigned(FHashArray^[i]) then
  960. a(FHashArray^[i]);
  961. end
  962. else
  963. if assigned(FRoot) then
  964. a(FRoot);
  965. end;
  966. procedure Tdictionary.foreach_static(proc2call:TNamedIndexStaticCallback);
  967. procedure a(p:TNamedIndexItem);
  968. begin
  969. proc2call(p);
  970. if assigned(p.FLeft) then
  971. a(p.FLeft);
  972. if assigned(p.FRight) then
  973. a(p.FRight);
  974. end;
  975. var
  976. i : integer;
  977. begin
  978. if assigned(FHashArray) then
  979. begin
  980. for i:=low(FHashArray^) to high(FHashArray^) do
  981. if assigned(FHashArray^[i]) then
  982. a(FHashArray^[i]);
  983. end
  984. else
  985. if assigned(FRoot) then
  986. a(FRoot);
  987. end;
  988. function Tdictionary.insert(obj:TNamedIndexItem):TNamedIndexItem;
  989. begin
  990. obj.FSpeedValue:=GetSpeedValue(obj.FName^);
  991. if assigned(FHashArray) then
  992. insert:=insertNode(obj,FHashArray^[obj.SpeedValue mod hasharraysize])
  993. else
  994. insert:=insertNode(obj,FRoot);
  995. end;
  996. function tdictionary.insertNode(NewNode:TNamedIndexItem;var currNode:TNamedIndexItem):TNamedIndexItem;
  997. begin
  998. if currNode=nil then
  999. begin
  1000. currNode:=NewNode;
  1001. insertNode:=NewNode;
  1002. end
  1003. { First check SpeedValue, to allow a fast insert }
  1004. else
  1005. if currNode.SpeedValue>NewNode.SpeedValue then
  1006. insertNode:=insertNode(NewNode,currNode.FRight)
  1007. else
  1008. if currNode.SpeedValue<NewNode.SpeedValue then
  1009. insertNode:=insertNode(NewNode,currNode.FLeft)
  1010. else
  1011. begin
  1012. if currNode.FName^>NewNode.FName^ then
  1013. insertNode:=insertNode(NewNode,currNode.FRight)
  1014. else
  1015. if currNode.FName^<NewNode.FName^ then
  1016. insertNode:=insertNode(NewNode,currNode.FLeft)
  1017. else
  1018. begin
  1019. if (replace_existing or delete_doubles) and
  1020. assigned(currNode) then
  1021. begin
  1022. NewNode.FLeft:=currNode.FLeft;
  1023. NewNode.FRight:=currNode.FRight;
  1024. if delete_doubles then
  1025. begin
  1026. currnode.FLeft:=nil;
  1027. currnode.FRight:=nil;
  1028. currnode.free;
  1029. end;
  1030. currNode:=NewNode;
  1031. insertNode:=NewNode;
  1032. end
  1033. else
  1034. insertNode:=currNode;
  1035. end;
  1036. end;
  1037. end;
  1038. procedure tdictionary.inserttree(currtree,currroot:TNamedIndexItem);
  1039. begin
  1040. if assigned(currtree) then
  1041. begin
  1042. inserttree(currtree.FLeft,currroot);
  1043. inserttree(currtree.FRight,currroot);
  1044. currtree.FRight:=nil;
  1045. currtree.FLeft:=nil;
  1046. insertNode(currtree,currroot);
  1047. end;
  1048. end;
  1049. function tdictionary.rename(const olds,News : string):TNamedIndexItem;
  1050. var
  1051. spdval : cardinal;
  1052. lasthp,
  1053. hp,hp2,hp3 : TNamedIndexItem;
  1054. begin
  1055. spdval:=GetSpeedValue(olds);
  1056. if assigned(FHashArray) then
  1057. hp:=FHashArray^[spdval mod hasharraysize]
  1058. else
  1059. hp:=FRoot;
  1060. lasthp:=nil;
  1061. while assigned(hp) do
  1062. begin
  1063. if spdval>hp.SpeedValue then
  1064. begin
  1065. lasthp:=hp;
  1066. hp:=hp.FLeft
  1067. end
  1068. else
  1069. if spdval<hp.SpeedValue then
  1070. begin
  1071. lasthp:=hp;
  1072. hp:=hp.FRight
  1073. end
  1074. else
  1075. begin
  1076. if (hp.FName^=olds) then
  1077. begin
  1078. { Get in hp2 the replacer for the root or hasharr }
  1079. hp2:=hp.FLeft;
  1080. hp3:=hp.FRight;
  1081. if not assigned(hp2) then
  1082. begin
  1083. hp2:=hp.FRight;
  1084. hp3:=hp.FLeft;
  1085. end;
  1086. { remove entry from the tree }
  1087. if assigned(lasthp) then
  1088. begin
  1089. if lasthp.FLeft=hp then
  1090. lasthp.FLeft:=hp2
  1091. else
  1092. lasthp.FRight:=hp2;
  1093. end
  1094. else
  1095. begin
  1096. if assigned(FHashArray) then
  1097. FHashArray^[spdval mod hasharraysize]:=hp2
  1098. else
  1099. FRoot:=hp2;
  1100. end;
  1101. { reinsert the hp3 in the tree from hp2 }
  1102. inserttree(hp3,hp2);
  1103. { reset Node with New values }
  1104. hp.FLeft:=nil;
  1105. hp.FRight:=nil;
  1106. stringdispose(hp.FName);
  1107. hp.FName:=stringdup(newS);
  1108. hp.FSpeedValue:=GetSpeedValue(newS);
  1109. { reinsert }
  1110. if assigned(FHashArray) then
  1111. rename:=insertNode(hp,FHashArray^[hp.SpeedValue mod hasharraysize])
  1112. else
  1113. rename:=insertNode(hp,FRoot);
  1114. exit;
  1115. end
  1116. else
  1117. if olds>hp.FName^ then
  1118. begin
  1119. lasthp:=hp;
  1120. hp:=hp.FLeft
  1121. end
  1122. else
  1123. begin
  1124. lasthp:=hp;
  1125. hp:=hp.FRight;
  1126. end;
  1127. end;
  1128. end;
  1129. end;
  1130. function Tdictionary.search(const s:string):TNamedIndexItem;
  1131. begin
  1132. search:=speedsearch(s,GetSpeedValue(s));
  1133. end;
  1134. function Tdictionary.speedsearch(const s:string;SpeedValue:cardinal):TNamedIndexItem;
  1135. var
  1136. NewNode:TNamedIndexItem;
  1137. begin
  1138. if assigned(FHashArray) then
  1139. NewNode:=FHashArray^[SpeedValue mod hasharraysize]
  1140. else
  1141. NewNode:=FRoot;
  1142. while assigned(NewNode) do
  1143. begin
  1144. if SpeedValue>NewNode.SpeedValue then
  1145. NewNode:=NewNode.FLeft
  1146. else
  1147. if SpeedValue<NewNode.SpeedValue then
  1148. NewNode:=NewNode.FRight
  1149. else
  1150. begin
  1151. if (NewNode.FName^=s) then
  1152. begin
  1153. speedsearch:=NewNode;
  1154. exit;
  1155. end
  1156. else
  1157. if s>NewNode.FName^ then
  1158. NewNode:=NewNode.FLeft
  1159. else
  1160. NewNode:=NewNode.FRight;
  1161. end;
  1162. end;
  1163. speedsearch:=nil;
  1164. end;
  1165. {****************************************************************************
  1166. tsingleList
  1167. ****************************************************************************}
  1168. constructor tsingleList.create;
  1169. begin
  1170. First:=nil;
  1171. last:=nil;
  1172. end;
  1173. procedure tsingleList.reset;
  1174. begin
  1175. First:=nil;
  1176. last:=nil;
  1177. end;
  1178. procedure tsingleList.clear;
  1179. var
  1180. hp,hp2 : TNamedIndexItem;
  1181. begin
  1182. hp:=First;
  1183. while assigned(hp) do
  1184. begin
  1185. hp2:=hp;
  1186. hp:=hp.FListNext;
  1187. hp2.free;
  1188. end;
  1189. First:=nil;
  1190. last:=nil;
  1191. end;
  1192. procedure tsingleList.insert(p:TNamedIndexItem);
  1193. begin
  1194. if not assigned(First) then
  1195. First:=p
  1196. else
  1197. last.FListNext:=p;
  1198. last:=p;
  1199. p.FListNext:=nil;
  1200. end;
  1201. {****************************************************************************
  1202. tindexarray
  1203. ****************************************************************************}
  1204. constructor tindexarray.create(Agrowsize:integer);
  1205. begin
  1206. growsize:=Agrowsize;
  1207. size:=0;
  1208. count:=0;
  1209. data:=nil;
  1210. First:=nil;
  1211. noclear:=false;
  1212. end;
  1213. destructor tindexarray.destroy;
  1214. begin
  1215. if assigned(data) then
  1216. begin
  1217. if not noclear then
  1218. clear;
  1219. freemem(data);
  1220. data:=nil;
  1221. end;
  1222. end;
  1223. function tindexarray.search(nr:integer):TNamedIndexItem;
  1224. begin
  1225. if nr<=count then
  1226. search:=data^[nr]
  1227. else
  1228. search:=nil;
  1229. end;
  1230. procedure tindexarray.clear;
  1231. var
  1232. i : integer;
  1233. begin
  1234. for i:=1 to count do
  1235. if assigned(data^[i]) then
  1236. begin
  1237. data^[i].free;
  1238. data^[i]:=nil;
  1239. end;
  1240. count:=0;
  1241. First:=nil;
  1242. end;
  1243. procedure tindexarray.foreach(proc2call : Tnamedindexcallback);
  1244. var
  1245. i : integer;
  1246. begin
  1247. for i:=1 to count do
  1248. if assigned(data^[i]) then
  1249. proc2call(data^[i]);
  1250. end;
  1251. procedure tindexarray.foreach_static(proc2call : Tnamedindexstaticcallback);
  1252. var
  1253. i : integer;
  1254. begin
  1255. for i:=1 to count do
  1256. if assigned(data^[i]) then
  1257. proc2call(data^[i]);
  1258. end;
  1259. procedure tindexarray.grow(gsize:integer);
  1260. var
  1261. osize : integer;
  1262. begin
  1263. osize:=size;
  1264. inc(size,gsize);
  1265. reallocmem(data,size*4);
  1266. fillchar(data^[osize+1],gsize*4,0);
  1267. end;
  1268. procedure tindexarray.deleteindex(p:TNamedIndexItem);
  1269. var
  1270. i : integer;
  1271. begin
  1272. i:=p.Findexnr;
  1273. { update counter }
  1274. if i=count then
  1275. dec(count);
  1276. { update Linked List }
  1277. while (i>0) do
  1278. begin
  1279. dec(i);
  1280. if (i>0) and assigned(data^[i]) then
  1281. begin
  1282. data^[i].FindexNext:=data^[p.Findexnr].FindexNext;
  1283. break;
  1284. end;
  1285. end;
  1286. if i=0 then
  1287. First:=p.FindexNext;
  1288. data^[p.FIndexnr]:=nil;
  1289. { clear entry }
  1290. p.FIndexnr:=-1;
  1291. p.FIndexNext:=nil;
  1292. end;
  1293. procedure tindexarray.delete(var p:TNamedIndexItem);
  1294. begin
  1295. deleteindex(p);
  1296. p.free;
  1297. p:=nil;
  1298. end;
  1299. procedure tindexarray.insert(p:TNamedIndexItem);
  1300. var
  1301. i : integer;
  1302. begin
  1303. if p.FIndexnr=-1 then
  1304. begin
  1305. inc(count);
  1306. p.FIndexnr:=count;
  1307. end;
  1308. if p.FIndexnr>count then
  1309. count:=p.FIndexnr;
  1310. if count>size then
  1311. grow(((count div growsize)+1)*growsize);
  1312. Assert(not assigned(data^[p.FIndexnr]) or (p=data^[p.FIndexnr]));
  1313. data^[p.FIndexnr]:=p;
  1314. { update Linked List backward }
  1315. i:=p.FIndexnr;
  1316. while (i>0) do
  1317. begin
  1318. dec(i);
  1319. if (i>0) and assigned(data^[i]) then
  1320. begin
  1321. data^[i].FIndexNext:=p;
  1322. break;
  1323. end;
  1324. end;
  1325. if i=0 then
  1326. First:=p;
  1327. { update Linked List forward }
  1328. i:=p.FIndexnr;
  1329. while (i<=count) do
  1330. begin
  1331. inc(i);
  1332. if (i<=count) and assigned(data^[i]) then
  1333. begin
  1334. p.FIndexNext:=data^[i];
  1335. exit;
  1336. end;
  1337. end;
  1338. if i>count then
  1339. p.FIndexNext:=nil;
  1340. end;
  1341. {****************************************************************************
  1342. tdynamicarray
  1343. ****************************************************************************}
  1344. constructor tdynamicarray.create(Ablocksize:integer);
  1345. begin
  1346. FPosn:=0;
  1347. FPosnblock:=nil;
  1348. FFirstblock:=nil;
  1349. FLastblock:=nil;
  1350. Fblocksize:=Ablocksize;
  1351. grow;
  1352. end;
  1353. destructor tdynamicarray.destroy;
  1354. var
  1355. hp : pdynamicblock;
  1356. begin
  1357. while assigned(FFirstblock) do
  1358. begin
  1359. hp:=FFirstblock;
  1360. FFirstblock:=FFirstblock^.Next;
  1361. freemem(hp,blocksize+dynamicblockbasesize);
  1362. end;
  1363. end;
  1364. function tdynamicarray.size:integer;
  1365. begin
  1366. if assigned(FLastblock) then
  1367. size:=FLastblock^.pos+FLastblock^.used
  1368. else
  1369. size:=0;
  1370. end;
  1371. procedure tdynamicarray.grow;
  1372. var
  1373. nblock : pdynamicblock;
  1374. begin
  1375. Getmem(nblock,blocksize+dynamicblockbasesize);
  1376. if not assigned(FFirstblock) then
  1377. begin
  1378. FFirstblock:=nblock;
  1379. FPosnblock:=nblock;
  1380. nblock^.pos:=0;
  1381. end
  1382. else
  1383. begin
  1384. FLastblock^.Next:=nblock;
  1385. nblock^.pos:=FLastblock^.pos+FLastblock^.used;
  1386. end;
  1387. nblock^.used:=0;
  1388. nblock^.Next:=nil;
  1389. fillchar(nblock^.data,blocksize,0);
  1390. FLastblock:=nblock;
  1391. end;
  1392. procedure tdynamicarray.align(i:integer);
  1393. var
  1394. j : integer;
  1395. begin
  1396. j:=(FPosn mod i);
  1397. if j<>0 then
  1398. begin
  1399. j:=i-j;
  1400. if FPosnblock^.used+j>blocksize then
  1401. begin
  1402. dec(j,blocksize-FPosnblock^.used);
  1403. FPosnblock^.used:=blocksize;
  1404. grow;
  1405. FPosnblock:=FLastblock;
  1406. end;
  1407. inc(FPosnblock^.used,j);
  1408. inc(FPosn,j);
  1409. end;
  1410. end;
  1411. procedure tdynamicarray.seek(i:integer);
  1412. begin
  1413. if (i<FPosnblock^.pos) or (i>=FPosnblock^.pos+blocksize) then
  1414. begin
  1415. { set FPosnblock correct if the size is bigger then
  1416. the current block }
  1417. if FPosnblock^.pos>i then
  1418. FPosnblock:=FFirstblock;
  1419. while assigned(FPosnblock) do
  1420. begin
  1421. if FPosnblock^.pos+blocksize>i then
  1422. break;
  1423. FPosnblock:=FPosnblock^.Next;
  1424. end;
  1425. { not found ? then increase blocks }
  1426. if not assigned(FPosnblock) then
  1427. begin
  1428. { the current FLastblock is now also fully used }
  1429. FLastblock^.used:=blocksize;
  1430. repeat
  1431. grow;
  1432. FPosnblock:=FLastblock;
  1433. until FPosnblock^.pos+blocksize>=i;
  1434. end;
  1435. end;
  1436. FPosn:=i;
  1437. if FPosn mod blocksize>FPosnblock^.used then
  1438. FPosnblock^.used:=FPosn mod blocksize;
  1439. end;
  1440. procedure tdynamicarray.write(const d;len:integer);
  1441. var
  1442. p : pchar;
  1443. i,j : integer;
  1444. begin
  1445. p:=pchar(@d);
  1446. while (len>0) do
  1447. begin
  1448. i:=FPosn mod blocksize;
  1449. if i+len>=blocksize then
  1450. begin
  1451. j:=blocksize-i;
  1452. move(p^,FPosnblock^.data[i],j);
  1453. inc(p,j);
  1454. inc(FPosn,j);
  1455. dec(len,j);
  1456. FPosnblock^.used:=blocksize;
  1457. if assigned(FPosnblock^.Next) then
  1458. FPosnblock:=FPosnblock^.Next
  1459. else
  1460. begin
  1461. grow;
  1462. FPosnblock:=FLastblock;
  1463. end;
  1464. end
  1465. else
  1466. begin
  1467. move(p^,FPosnblock^.data[i],len);
  1468. inc(p,len);
  1469. inc(FPosn,len);
  1470. i:=FPosn mod blocksize;
  1471. if i>FPosnblock^.used then
  1472. FPosnblock^.used:=i;
  1473. len:=0;
  1474. end;
  1475. end;
  1476. end;
  1477. procedure tdynamicarray.writestr(const s:string);
  1478. begin
  1479. write(s[1],length(s));
  1480. end;
  1481. function tdynamicarray.read(var d;len:integer):integer;
  1482. var
  1483. p : pchar;
  1484. i,j,res : integer;
  1485. begin
  1486. res:=0;
  1487. p:=pchar(@d);
  1488. while (len>0) do
  1489. begin
  1490. i:=FPosn mod blocksize;
  1491. if i+len>=FPosnblock^.used then
  1492. begin
  1493. j:=FPosnblock^.used-i;
  1494. move(FPosnblock^.data[i],p^,j);
  1495. inc(p,j);
  1496. inc(FPosn,j);
  1497. inc(res,j);
  1498. dec(len,j);
  1499. if assigned(FPosnblock^.Next) then
  1500. FPosnblock:=FPosnblock^.Next
  1501. else
  1502. break;
  1503. end
  1504. else
  1505. begin
  1506. move(FPosnblock^.data[i],p^,len);
  1507. inc(p,len);
  1508. inc(FPosn,len);
  1509. inc(res,len);
  1510. len:=0;
  1511. end;
  1512. end;
  1513. read:=res;
  1514. end;
  1515. procedure tdynamicarray.readstream(f:TCStream;maxlen:longint);
  1516. var
  1517. i,left : integer;
  1518. begin
  1519. if maxlen=-1 then
  1520. maxlen:=maxlongint;
  1521. repeat
  1522. left:=blocksize-FPosnblock^.used;
  1523. if left>maxlen then
  1524. left:=maxlen;
  1525. i:=f.Read(FPosnblock^.data[FPosnblock^.used],left);
  1526. dec(maxlen,i);
  1527. inc(FPosnblock^.used,i);
  1528. if FPosnblock^.used=blocksize then
  1529. begin
  1530. if assigned(FPosnblock^.Next) then
  1531. FPosnblock:=FPosnblock^.Next
  1532. else
  1533. begin
  1534. grow;
  1535. FPosnblock:=FLastblock;
  1536. end;
  1537. end;
  1538. until (i<left) or (maxlen=0);
  1539. end;
  1540. procedure tdynamicarray.writestream(f:TCStream);
  1541. var
  1542. hp : pdynamicblock;
  1543. begin
  1544. hp:=FFirstblock;
  1545. while assigned(hp) do
  1546. begin
  1547. f.Write(hp^.data,hp^.used);
  1548. hp:=hp^.Next;
  1549. end;
  1550. end;
  1551. end.
  1552. {
  1553. $Log$
  1554. Revision 1.8 2001-11-05 14:16:25 jonas
  1555. * reduced memory usage by about 10% and increased speed by about 15%
  1556. Revision 1.7 2001/05/04 19:50:04 peter
  1557. * fixed dynamicarray.seek() with pos equals multiple of $10000
  1558. Revision 1.6 2001/04/13 01:22:06 peter
  1559. * symtable change to classes
  1560. * range check generation and errors fixed, make cycle DEBUG=1 works
  1561. * memory leaks fixed
  1562. Revision 1.5 2001/03/13 18:45:06 peter
  1563. * fixed some memory leaks
  1564. Revision 1.4 2001/03/05 21:40:01 peter
  1565. * fixed tdynamicarray.readstream
  1566. Revision 1.3 2000/12/29 21:57:27 peter
  1567. * 'classified' tdictionary, but leave it within an define
  1568. Revision 1.2 2000/12/25 00:07:25 peter
  1569. + new tlinkedlist class (merge of old tstringqueue,tcontainer and
  1570. tlinkedlist objects)
  1571. Revision 1.1 2000/12/24 12:25:31 peter
  1572. + cstreams unit
  1573. * dynamicarray object to class
  1574. }