cclasses.pas 50 KB

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