cobjects.pas 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683
  1. {
  2. $Id$
  3. Copyright (c) 1998-2000 by Florian Klaempfl
  4. This module provides some basic objects
  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 cobjects;
  19. {$i defines.inc}
  20. interface
  21. uses
  22. cutils;
  23. const
  24. { the real size will be [-hasharray..hasharray] ! }
  25. hasharraysize = 2047;
  26. type
  27. pfileposinfo = ^tfileposinfo;
  28. tfileposinfo = record
  29. line : longint;
  30. column : word;
  31. fileindex : word;
  32. end;
  33. pmemdebug = ^tmemdebug;
  34. tmemdebug = object
  35. constructor init(const s:string);
  36. destructor done;
  37. procedure show;
  38. private
  39. startmem : longint;
  40. infostr : string[40];
  41. end;
  42. plinkedlist_item = ^tlinkedlist_item;
  43. tlinkedlist_item = object
  44. next,previous : plinkedlist_item;
  45. { does nothing }
  46. constructor init;
  47. destructor done;virtual;
  48. function getcopy:plinkedlist_item;virtual;
  49. end;
  50. pstring_item = ^tstring_item;
  51. tstring_item = object(tlinkedlist_item)
  52. str : pstring;
  53. constructor init(const s : string);
  54. destructor done;virtual;
  55. end;
  56. { this implements a double linked list }
  57. plinkedlist = ^tlinkedlist;
  58. tlinkedlist = object
  59. first,last : plinkedlist_item;
  60. constructor init;
  61. destructor done;
  62. { disposes the items of the list }
  63. procedure clear;
  64. { concats a new item at the end }
  65. procedure concat(p : plinkedlist_item);
  66. { inserts a new item at the begin }
  67. procedure insert(p : plinkedlist_item);
  68. { inserts another list at the begin and make this list empty }
  69. procedure insertlist(p : plinkedlist);
  70. { concats another list at the end and make this list empty }
  71. procedure concatlist(p : plinkedlist);
  72. procedure concatlistcopy(p : plinkedlist);
  73. { removes p from the list (p isn't disposed) }
  74. { it's not tested if p is in the list ! }
  75. procedure remove(p : plinkedlist_item);
  76. { is the linkedlist empty ? }
  77. function empty:boolean;
  78. { items in the list }
  79. function count:longint;
  80. end;
  81. { some help data types }
  82. pstringqueueitem = ^tstringqueueitem;
  83. tstringqueueitem = object
  84. data : pstring;
  85. next : pstringqueueitem;
  86. end;
  87. { String Queue}
  88. PStringQueue=^TStringQueue;
  89. TStringQueue=object
  90. first,last : PStringqueueItem;
  91. constructor Init;
  92. destructor Done;
  93. function Empty:boolean;
  94. function Get:string;
  95. function Find(const s:string):PStringqueueItem;
  96. function Delete(const s:string):boolean;
  97. procedure Insert(const s:string);
  98. procedure Concat(const s:string);
  99. procedure Clear;
  100. end;
  101. { containeritem }
  102. pcontaineritem = ^tcontaineritem;
  103. tcontaineritem = object
  104. next : pcontaineritem;
  105. constructor init;
  106. destructor done;virtual;
  107. end;
  108. { container }
  109. pcontainer = ^tcontainer;
  110. tcontainer = object
  111. root,
  112. last : pcontaineritem;
  113. constructor init;
  114. destructor done;
  115. { true when the container is empty }
  116. function empty:boolean;
  117. { amount of strings in the container }
  118. function count:longint;
  119. { inserts a string }
  120. procedure insert(item:pcontaineritem);
  121. { gets a string }
  122. function get:pcontaineritem;
  123. { deletes all items }
  124. procedure clear;
  125. end;
  126. { containeritem }
  127. pstringcontaineritem = ^tstringcontaineritem;
  128. tstringcontaineritem = object(tcontaineritem)
  129. data : pstring;
  130. file_info : tfileposinfo;
  131. constructor init(const s:string);
  132. constructor Init_TokenInfo(const s:string;const pos:tfileposinfo);
  133. destructor done;virtual;
  134. end;
  135. { string container }
  136. pstringcontainer = ^tstringcontainer;
  137. tstringcontainer = object(tcontainer)
  138. doubles : boolean; { if this is set to true, doubles are allowed }
  139. constructor init;
  140. constructor init_no_double;
  141. procedure insert(const s : string);
  142. procedure insert_with_tokeninfo(const s : string;const file_info : tfileposinfo);
  143. { gets a string }
  144. function get : string;
  145. function get_with_tokeninfo(var file_info : tfileposinfo) : string;
  146. { true if string is in the container }
  147. function find(const s:string):boolean;
  148. end;
  149. { namedindexobect for use with dictionary and indexarray }
  150. Pnamedindexobject=^Tnamedindexobject;
  151. Tnamedindexobject=object
  152. { indexarray }
  153. indexnr : longint;
  154. indexnext : Pnamedindexobject;
  155. { dictionary }
  156. _name : Pstring;
  157. _valuename : Pstring; { uppercase name }
  158. left,right : Pnamedindexobject;
  159. speedvalue : longint;
  160. { singlelist }
  161. listnext : Pnamedindexobject;
  162. constructor init;
  163. constructor initname(const n:string);
  164. destructor done;virtual;
  165. procedure setname(const n:string);virtual;
  166. function name:string;virtual;
  167. end;
  168. Pdictionaryhasharray=^Tdictionaryhasharray;
  169. Tdictionaryhasharray=array[-hasharraysize..hasharraysize] of Pnamedindexobject;
  170. Tnamedindexcallback = procedure(p:Pnamedindexobject);
  171. Pdictionary=^Tdictionary;
  172. Tdictionary=object
  173. noclear : boolean;
  174. replace_existing : boolean;
  175. constructor init;
  176. destructor done;virtual;
  177. procedure usehash;
  178. procedure clear;
  179. function delete(const s:string):Pnamedindexobject;
  180. function empty:boolean;
  181. procedure foreach(proc2call:Tnamedindexcallback);
  182. function insert(obj:Pnamedindexobject):Pnamedindexobject;
  183. function rename(const olds,news : string):Pnamedindexobject;
  184. function search(const s:string):Pnamedindexobject;
  185. function speedsearch(const s:string;speedvalue:longint):Pnamedindexobject;
  186. private
  187. root : Pnamedindexobject;
  188. hasharray : Pdictionaryhasharray;
  189. procedure cleartree(obj:Pnamedindexobject);
  190. function insertnode(newnode:Pnamedindexobject;var currnode:Pnamedindexobject):Pnamedindexobject;
  191. procedure inserttree(currtree,currroot:Pnamedindexobject);
  192. end;
  193. psinglelist=^tsinglelist;
  194. tsinglelist=object
  195. first,
  196. last : Pnamedindexobject;
  197. constructor init;
  198. destructor done;
  199. procedure reset;
  200. procedure clear;
  201. procedure insert(p:Pnamedindexobject);
  202. end;
  203. tindexobjectarray=array[1..16000] of Pnamedindexobject;
  204. Pnamedindexobjectarray=^tindexobjectarray;
  205. pindexarray=^tindexarray;
  206. tindexarray=object
  207. noclear : boolean;
  208. first : Pnamedindexobject;
  209. count : longint;
  210. constructor init(Agrowsize:longint);
  211. destructor done;
  212. procedure clear;
  213. procedure foreach(proc2call : Tnamedindexcallback);
  214. procedure deleteindex(p:Pnamedindexobject);
  215. procedure delete(var p:Pnamedindexobject);
  216. procedure insert(p:Pnamedindexobject);
  217. function search(nr:longint):Pnamedindexobject;
  218. private
  219. growsize,
  220. size : longint;
  221. data : Pnamedindexobjectarray;
  222. procedure grow(gsize:longint);
  223. end;
  224. {$ifdef fixLeaksOnError}
  225. PStackItem = ^TStackItem;
  226. TStackItem = record
  227. next: PStackItem;
  228. data: pointer;
  229. end;
  230. PStack = ^TStack;
  231. TStack = object
  232. constructor init;
  233. destructor done;
  234. procedure push(p: pointer);
  235. function pop: pointer;
  236. function top: pointer;
  237. function isEmpty: boolean;
  238. private
  239. head: PStackItem;
  240. end;
  241. {$endif fixLeaksOnError}
  242. implementation
  243. {*****************************************************************************
  244. Memory debug
  245. *****************************************************************************}
  246. constructor tmemdebug.init(const s:string);
  247. begin
  248. infostr:=s;
  249. {$ifdef Delphi}
  250. startmem:=0;
  251. {$else}
  252. startmem:=memavail;
  253. {$endif Delphi}
  254. end;
  255. procedure tmemdebug.show;
  256. {$ifndef Delphi}
  257. var
  258. l : longint;
  259. {$endif}
  260. begin
  261. {$ifndef Delphi}
  262. write('memory [',infostr,'] ');
  263. l:=memavail;
  264. if l>startmem then
  265. writeln(l-startmem,' released')
  266. else
  267. writeln(startmem-l,' allocated');
  268. {$endif Delphi}
  269. end;
  270. destructor tmemdebug.done;
  271. begin
  272. show;
  273. end;
  274. {*****************************************************************************
  275. Stack
  276. *****************************************************************************}
  277. {$ifdef fixLeaksOnError}
  278. constructor TStack.init;
  279. begin
  280. head := nil;
  281. end;
  282. procedure TStack.push(p: pointer);
  283. var s: PStackItem;
  284. begin
  285. new(s);
  286. s^.data := p;
  287. s^.next := head;
  288. head := s;
  289. end;
  290. function TStack.pop: pointer;
  291. var s: PStackItem;
  292. begin
  293. pop := top;
  294. if assigned(head) then
  295. begin
  296. s := head^.next;
  297. dispose(head);
  298. head := s;
  299. end
  300. end;
  301. function TStack.top: pointer;
  302. begin
  303. if not isEmpty then
  304. top := head^.data
  305. else top := NIL;
  306. end;
  307. function TStack.isEmpty: boolean;
  308. begin
  309. isEmpty := head = nil;
  310. end;
  311. destructor TStack.done;
  312. var temp: PStackItem;
  313. begin
  314. while head <> nil do
  315. begin
  316. temp := head^.next;
  317. dispose(head);
  318. head := temp;
  319. end;
  320. end;
  321. {$endif fixLeaksOnError}
  322. {****************************************************************************
  323. TStringQueue
  324. ****************************************************************************}
  325. constructor TStringQueue.Init;
  326. begin
  327. first:=nil;
  328. last:=nil;
  329. end;
  330. function TStringQueue.Empty:boolean;
  331. begin
  332. Empty:=(first=nil);
  333. end;
  334. function TStringQueue.Get:string;
  335. var
  336. newnode : pstringqueueitem;
  337. begin
  338. if first=nil then
  339. begin
  340. Get:='';
  341. exit;
  342. end;
  343. Get:=first^.data^;
  344. stringdispose(first^.data);
  345. newnode:=first;
  346. first:=first^.next;
  347. dispose(newnode);
  348. end;
  349. function TStringQueue.Find(const s:string):PStringqueueItem;
  350. var
  351. p : PStringqueueItem;
  352. begin
  353. p:=first;
  354. while assigned(p) do
  355. begin
  356. if p^.data^=s then
  357. break;
  358. p:=p^.next;
  359. end;
  360. Find:=p;
  361. end;
  362. function TStringQueue.Delete(const s:string):boolean;
  363. var
  364. prev,p : PStringqueueItem;
  365. begin
  366. Delete:=false;
  367. prev:=nil;
  368. p:=first;
  369. while assigned(p) do
  370. begin
  371. if p^.data^=s then
  372. begin
  373. if p=last then
  374. last:=prev;
  375. if assigned(prev) then
  376. prev^.next:=p^.next
  377. else
  378. first:=p^.next;
  379. dispose(p^.data);
  380. dispose(p);
  381. Delete:=true;
  382. exit;
  383. end;
  384. prev:=p;
  385. p:=p^.next;
  386. end;
  387. end;
  388. procedure TStringQueue.Insert(const s:string);
  389. var
  390. newnode : pstringqueueitem;
  391. begin
  392. new(newnode);
  393. newnode^.next:=first;
  394. newnode^.data:=stringdup(s);
  395. first:=newnode;
  396. if last=nil then
  397. last:=newnode;
  398. end;
  399. procedure TStringQueue.Concat(const s:string);
  400. var
  401. newnode : pstringqueueitem;
  402. begin
  403. new(newnode);
  404. newnode^.next:=nil;
  405. newnode^.data:=stringdup(s);
  406. if first=nil then
  407. first:=newnode
  408. else
  409. last^.next:=newnode;
  410. last:=newnode;
  411. end;
  412. procedure TStringQueue.Clear;
  413. var
  414. newnode : pstringqueueitem;
  415. begin
  416. while (first<>nil) do
  417. begin
  418. newnode:=first;
  419. stringdispose(first^.data);
  420. first:=first^.next;
  421. dispose(newnode);
  422. end;
  423. last:=nil;
  424. end;
  425. destructor TStringQueue.Done;
  426. begin
  427. Clear;
  428. end;
  429. {****************************************************************************
  430. TContainerItem
  431. ****************************************************************************}
  432. constructor TContainerItem.Init;
  433. begin
  434. end;
  435. destructor TContainerItem.Done;
  436. begin
  437. end;
  438. {****************************************************************************
  439. TStringContainerItem
  440. ****************************************************************************}
  441. constructor TStringContainerItem.Init(const s:string);
  442. begin
  443. inherited Init;
  444. data:=stringdup(s);
  445. file_info.fileindex:=0;
  446. file_info.line:=0;
  447. file_info.column:=0;
  448. end;
  449. constructor TStringContainerItem.Init_TokenInfo(const s:string;const pos:tfileposinfo);
  450. begin
  451. inherited Init;
  452. data:=stringdup(s);
  453. file_info:=pos;
  454. end;
  455. destructor TStringContainerItem.Done;
  456. begin
  457. stringdispose(data);
  458. end;
  459. {****************************************************************************
  460. TCONTAINER
  461. ****************************************************************************}
  462. constructor tcontainer.init;
  463. begin
  464. root:=nil;
  465. last:=nil;
  466. end;
  467. destructor tcontainer.done;
  468. begin
  469. clear;
  470. end;
  471. function tcontainer.empty:boolean;
  472. begin
  473. empty:=(root=nil);
  474. end;
  475. function tcontainer.count:longint;
  476. var
  477. i : longint;
  478. p : pcontaineritem;
  479. begin
  480. i:=0;
  481. p:=root;
  482. while assigned(p) do
  483. begin
  484. p:=p^.next;
  485. inc(i);
  486. end;
  487. count:=i;
  488. end;
  489. procedure tcontainer.insert(item:pcontaineritem);
  490. begin
  491. item^.next:=nil;
  492. if root=nil then
  493. root:=item
  494. else
  495. last^.next:=item;
  496. last:=item;
  497. end;
  498. procedure tcontainer.clear;
  499. var
  500. newnode : pcontaineritem;
  501. begin
  502. newnode:=root;
  503. while assigned(newnode) do
  504. begin
  505. root:=newnode^.next;
  506. dispose(newnode,done);
  507. newnode:=root;
  508. end;
  509. last:=nil;
  510. root:=nil;
  511. end;
  512. function tcontainer.get:pcontaineritem;
  513. begin
  514. if root=nil then
  515. get:=nil
  516. else
  517. begin
  518. get:=root;
  519. root:=root^.next;
  520. end;
  521. end;
  522. {****************************************************************************
  523. TSTRINGCONTAINER
  524. ****************************************************************************}
  525. constructor tstringcontainer.init;
  526. begin
  527. inherited init;
  528. doubles:=true;
  529. end;
  530. constructor tstringcontainer.init_no_double;
  531. begin
  532. inherited init;
  533. doubles:=false;
  534. end;
  535. procedure tstringcontainer.insert(const s : string);
  536. var
  537. newnode : pstringcontaineritem;
  538. begin
  539. if (s='') or
  540. ((not doubles) and find(s)) then
  541. exit;
  542. new(newnode,init(s));
  543. inherited insert(newnode);
  544. end;
  545. procedure tstringcontainer.insert_with_tokeninfo(const s : string; const file_info : tfileposinfo);
  546. var
  547. newnode : pstringcontaineritem;
  548. begin
  549. if (not doubles) and find(s) then
  550. exit;
  551. new(newnode,init_tokeninfo(s,file_info));
  552. inherited insert(newnode);
  553. end;
  554. function tstringcontainer.get : string;
  555. var
  556. p : pstringcontaineritem;
  557. begin
  558. p:=pstringcontaineritem(inherited get);
  559. if p=nil then
  560. get:=''
  561. else
  562. begin
  563. get:=p^.data^;
  564. dispose(p,done);
  565. end;
  566. end;
  567. function tstringcontainer.get_with_tokeninfo(var file_info : tfileposinfo) : string;
  568. var
  569. p : pstringcontaineritem;
  570. begin
  571. p:=pstringcontaineritem(inherited get);
  572. if p=nil then
  573. begin
  574. get_with_tokeninfo:='';
  575. file_info.fileindex:=0;
  576. file_info.line:=0;
  577. file_info.column:=0;
  578. end
  579. else
  580. begin
  581. get_with_tokeninfo:=p^.data^;
  582. file_info:=p^.file_info;
  583. dispose(p,done);
  584. end;
  585. end;
  586. function tstringcontainer.find(const s:string):boolean;
  587. var
  588. newnode : pstringcontaineritem;
  589. begin
  590. find:=false;
  591. newnode:=pstringcontaineritem(root);
  592. while assigned(newnode) do
  593. begin
  594. if newnode^.data^=s then
  595. begin
  596. find:=true;
  597. exit;
  598. end;
  599. newnode:=pstringcontaineritem(newnode^.next);
  600. end;
  601. end;
  602. {****************************************************************************
  603. TLINKEDLIST_ITEM
  604. ****************************************************************************}
  605. constructor tlinkedlist_item.init;
  606. begin
  607. previous:=nil;
  608. next:=nil;
  609. end;
  610. destructor tlinkedlist_item.done;
  611. begin
  612. end;
  613. function tlinkedlist_item.getcopy:plinkedlist_item;
  614. var
  615. l : longint;
  616. p : plinkedlist_item;
  617. begin
  618. l:=sizeof(self);
  619. getmem(p,l);
  620. move(self,p^,l);
  621. getcopy:=p;
  622. end;
  623. {****************************************************************************
  624. TSTRING_ITEM
  625. ****************************************************************************}
  626. constructor tstring_item.init(const s : string);
  627. begin
  628. str:=stringdup(s);
  629. end;
  630. destructor tstring_item.done;
  631. begin
  632. stringdispose(str);
  633. inherited done;
  634. end;
  635. {****************************************************************************
  636. TLINKEDLIST
  637. ****************************************************************************}
  638. constructor tlinkedlist.init;
  639. begin
  640. first:=nil;
  641. last:=nil;
  642. end;
  643. destructor tlinkedlist.done;
  644. begin
  645. clear;
  646. end;
  647. procedure tlinkedlist.clear;
  648. var
  649. newnode : plinkedlist_item;
  650. begin
  651. newnode:=first;
  652. while assigned(newnode) do
  653. begin
  654. first:=newnode^.next;
  655. dispose(newnode,done);
  656. newnode:=first;
  657. end;
  658. end;
  659. procedure tlinkedlist.insertlist(p : plinkedlist);
  660. begin
  661. { empty list ? }
  662. if not(assigned(p^.first)) then
  663. exit;
  664. p^.last^.next:=first;
  665. { we have a double linked list }
  666. if assigned(first) then
  667. first^.previous:=p^.last;
  668. first:=p^.first;
  669. if not(assigned(last)) then
  670. last:=p^.last;
  671. { p becomes empty }
  672. p^.first:=nil;
  673. p^.last:=nil;
  674. end;
  675. procedure tlinkedlist.concat(p : plinkedlist_item);
  676. begin
  677. if not(assigned(first)) then
  678. begin
  679. first:=p;
  680. p^.previous:=nil;
  681. p^.next:=nil;
  682. end
  683. else
  684. begin
  685. last^.next:=p;
  686. p^.previous:=last;
  687. p^.next:=nil;
  688. end;
  689. last:=p;
  690. end;
  691. procedure tlinkedlist.insert(p : plinkedlist_item);
  692. begin
  693. if not(assigned(first)) then
  694. begin
  695. last:=p;
  696. p^.previous:=nil;
  697. p^.next:=nil;
  698. end
  699. else
  700. begin
  701. first^.previous:=p;
  702. p^.previous:=nil;
  703. p^.next:=first;
  704. end;
  705. first:=p;
  706. end;
  707. procedure tlinkedlist.remove(p : plinkedlist_item);
  708. begin
  709. if not(assigned(p)) then
  710. exit;
  711. if (first=p) and (last=p) then
  712. begin
  713. first:=nil;
  714. last:=nil;
  715. end
  716. else if first=p then
  717. begin
  718. first:=p^.next;
  719. if assigned(first) then
  720. first^.previous:=nil;
  721. end
  722. else if last=p then
  723. begin
  724. last:=last^.previous;
  725. if assigned(last) then
  726. last^.next:=nil;
  727. end
  728. else
  729. begin
  730. p^.previous^.next:=p^.next;
  731. p^.next^.previous:=p^.previous;
  732. end;
  733. p^.next:=nil;
  734. p^.previous:=nil;
  735. end;
  736. procedure tlinkedlist.concatlist(p : plinkedlist);
  737. begin
  738. if not(assigned(p^.first)) then
  739. exit;
  740. if not(assigned(first)) then
  741. first:=p^.first
  742. else
  743. begin
  744. last^.next:=p^.first;
  745. p^.first^.previous:=last;
  746. end;
  747. last:=p^.last;
  748. { make p empty }
  749. p^.last:=nil;
  750. p^.first:=nil;
  751. end;
  752. procedure tlinkedlist.concatlistcopy(p : plinkedlist);
  753. var
  754. newnode,newnode2 : plinkedlist_item;
  755. begin
  756. newnode:=p^.first;
  757. while assigned(newnode) do
  758. begin
  759. newnode2:=newnode^.getcopy;
  760. if assigned(newnode2) then
  761. begin
  762. if not(assigned(first)) then
  763. begin
  764. first:=newnode2;
  765. newnode2^.previous:=nil;
  766. newnode2^.next:=nil;
  767. end
  768. else
  769. begin
  770. last^.next:=newnode2;
  771. newnode2^.previous:=last;
  772. newnode2^.next:=nil;
  773. end;
  774. last:=newnode2;
  775. end;
  776. newnode:=newnode^.next;
  777. end;
  778. end;
  779. function tlinkedlist.empty:boolean;
  780. begin
  781. empty:=(first=nil);
  782. end;
  783. function tlinkedlist.count:longint;
  784. var
  785. i : longint;
  786. hp : plinkedlist_item;
  787. begin
  788. hp:=first;
  789. i:=0;
  790. while assigned(hp) do
  791. begin
  792. inc(i);
  793. hp:=hp^.next;
  794. end;
  795. count:=i;
  796. end;
  797. {****************************************************************************
  798. Tnamedindexobject
  799. ****************************************************************************}
  800. constructor Tnamedindexobject.init;
  801. begin
  802. { index }
  803. indexnr:=-1;
  804. indexnext:=nil;
  805. { dictionary }
  806. left:=nil;
  807. right:=nil;
  808. _name:=nil;
  809. speedvalue:=-1;
  810. { list }
  811. listnext:=nil;
  812. end;
  813. constructor Tnamedindexobject.initname(const n:string);
  814. begin
  815. { index }
  816. indexnr:=-1;
  817. indexnext:=nil;
  818. { dictionary }
  819. left:=nil;
  820. right:=nil;
  821. speedvalue:=-1;
  822. _name:=stringdup(n);
  823. { list }
  824. listnext:=nil;
  825. end;
  826. destructor Tnamedindexobject.done;
  827. begin
  828. stringdispose(_name);
  829. end;
  830. procedure Tnamedindexobject.setname(const n:string);
  831. begin
  832. if speedvalue=-1 then
  833. begin
  834. if assigned(_name) then
  835. stringdispose(_name);
  836. _name:=stringdup(n);
  837. end;
  838. end;
  839. function Tnamedindexobject.name:string;
  840. begin
  841. if assigned(_name) then
  842. name:=_name^
  843. else
  844. name:='';
  845. end;
  846. {****************************************************************************
  847. TDICTIONARY
  848. ****************************************************************************}
  849. constructor Tdictionary.init;
  850. begin
  851. root:=nil;
  852. hasharray:=nil;
  853. noclear:=false;
  854. replace_existing:=false;
  855. end;
  856. procedure Tdictionary.usehash;
  857. begin
  858. if not(assigned(root)) and
  859. not(assigned(hasharray)) then
  860. begin
  861. new(hasharray);
  862. fillchar(hasharray^,sizeof(hasharray^),0);
  863. end;
  864. end;
  865. destructor Tdictionary.done;
  866. begin
  867. if not noclear then
  868. clear;
  869. if assigned(hasharray) then
  870. dispose(hasharray);
  871. end;
  872. procedure Tdictionary.cleartree(obj:Pnamedindexobject);
  873. begin
  874. if assigned(obj^.left) then
  875. cleartree(obj^.left);
  876. if assigned(obj^.right) then
  877. cleartree(obj^.right);
  878. dispose(obj,done);
  879. obj:=nil;
  880. end;
  881. procedure Tdictionary.clear;
  882. var
  883. w : longint;
  884. begin
  885. if assigned(root) then
  886. cleartree(root);
  887. if assigned(hasharray) then
  888. for w:=-hasharraysize to hasharraysize do
  889. if assigned(hasharray^[w]) then
  890. cleartree(hasharray^[w]);
  891. end;
  892. function Tdictionary.delete(const s:string):Pnamedindexobject;
  893. var p,speedvalue:longint;
  894. n:Pnamedindexobject;
  895. procedure insert_right_bottom(var root,Atree:Pnamedindexobject);
  896. begin
  897. while root^.right<>nil do
  898. root:=root^.right;
  899. root^.right:=Atree;
  900. end;
  901. function delete_from_tree(root:Pnamedindexobject):Pnamedindexobject;
  902. type leftright=(left,right);
  903. var lr:leftright;
  904. oldroot:Pnamedindexobject;
  905. begin
  906. oldroot:=nil;
  907. while (root<>nil) and (root^.speedvalue<>speedvalue) do
  908. begin
  909. oldroot:=root;
  910. if speedvalue<root^.speedvalue then
  911. begin
  912. root:=root^.right;
  913. lr:=right;
  914. end
  915. else
  916. begin
  917. root:=root^.left;
  918. lr:=left;
  919. end;
  920. end;
  921. while (root<>nil) and (root^._name^<>s) do
  922. begin
  923. oldroot:=root;
  924. if s<root^._name^ then
  925. begin
  926. root:=root^.right;
  927. lr:=right;
  928. end
  929. else
  930. begin
  931. root:=root^.left;
  932. lr:=left;
  933. end;
  934. end;
  935. if root^.left<>nil then
  936. begin
  937. {Now the node pointing to root must point to the left
  938. subtree of root. The right subtree of root must be
  939. connected to the right bottom of the left subtree.}
  940. if lr=left then
  941. oldroot^.left:=root^.left
  942. else
  943. oldroot^.right:=root^.left;
  944. if root^.right<>nil then
  945. insert_right_bottom(root^.left,root^.right);
  946. end
  947. else
  948. {There is no left subtree. So we can just replace the node to
  949. delete with the right subtree.}
  950. if lr=left then
  951. oldroot^.left:=root^.right
  952. else
  953. oldroot^.right:=root^.right;
  954. delete_from_tree:=root;
  955. end;
  956. begin
  957. speedvalue:=getspeedvalue(s);
  958. n:=root;
  959. if assigned(hasharray) then
  960. begin
  961. {First, check if the node to delete directly located under
  962. the hasharray.}
  963. p:=speedvalue mod hasharraysize;
  964. n:=hasharray^[p];
  965. if (n<>nil) and (n^.speedvalue=speedvalue) and
  966. (n^._name^=s) then
  967. begin
  968. {The node to delete is directly located under the
  969. hasharray. Make the hasharray point to the left
  970. subtree of the node and place the right subtree on
  971. the right-bottom of the left subtree.}
  972. if n^.left<>nil then
  973. begin
  974. hasharray^[p]:=n^.left;
  975. if n^.right<>nil then
  976. insert_right_bottom(n^.left,n^.right);
  977. end
  978. else
  979. hasharray^[p]:=n^.right;
  980. delete:=n;
  981. exit;
  982. end;
  983. end
  984. else
  985. begin
  986. {First check if the node to delete is the root.}
  987. if (root<>nil) and (n^.speedvalue=speedvalue)
  988. and (n^._name^=s) then
  989. begin
  990. if n^.left<>nil then
  991. begin
  992. root:=n^.left;
  993. if n^.right<>nil then
  994. insert_right_bottom(n^.left,n^.right);
  995. end
  996. else
  997. root:=n^.right;
  998. delete:=n;
  999. exit;
  1000. end;
  1001. end;
  1002. delete:=delete_from_tree(n);
  1003. end;
  1004. function Tdictionary.empty:boolean;
  1005. var
  1006. w : longint;
  1007. begin
  1008. if assigned(hasharray) then
  1009. begin
  1010. empty:=false;
  1011. for w:=-hasharraysize to hasharraysize do
  1012. if assigned(hasharray^[w]) then
  1013. exit;
  1014. empty:=true;
  1015. end
  1016. else
  1017. empty:=(root=nil);
  1018. end;
  1019. procedure Tdictionary.foreach(proc2call:Tnamedindexcallback);
  1020. procedure a(p:Pnamedindexobject);
  1021. begin
  1022. proc2call(p);
  1023. if assigned(p^.left) then
  1024. a(p^.left);
  1025. if assigned(p^.right) then
  1026. a(p^.right);
  1027. end;
  1028. var
  1029. i : longint;
  1030. begin
  1031. if assigned(hasharray) then
  1032. begin
  1033. for i:=-hasharraysize to hasharraysize do
  1034. if assigned(hasharray^[i]) then
  1035. a(hasharray^[i]);
  1036. end
  1037. else
  1038. if assigned(root) then
  1039. a(root);
  1040. end;
  1041. function Tdictionary.insert(obj:Pnamedindexobject):Pnamedindexobject;
  1042. begin
  1043. obj^.speedvalue:=getspeedvalue(obj^._name^);
  1044. if assigned(hasharray) then
  1045. insert:=insertnode(obj,hasharray^[obj^.speedvalue mod hasharraysize])
  1046. else
  1047. insert:=insertnode(obj,root);
  1048. end;
  1049. function tdictionary.insertnode(newnode:Pnamedindexobject;var currnode:Pnamedindexobject):Pnamedindexobject;
  1050. begin
  1051. if currnode=nil then
  1052. begin
  1053. currnode:=newnode;
  1054. insertnode:=newnode;
  1055. end
  1056. { first check speedvalue, to allow a fast insert }
  1057. else
  1058. if currnode^.speedvalue>newnode^.speedvalue then
  1059. insertnode:=insertnode(newnode,currnode^.right)
  1060. else
  1061. if currnode^.speedvalue<newnode^.speedvalue then
  1062. insertnode:=insertnode(newnode,currnode^.left)
  1063. else
  1064. begin
  1065. if currnode^._name^>newnode^._name^ then
  1066. insertnode:=insertnode(newnode,currnode^.right)
  1067. else
  1068. if currnode^._name^<newnode^._name^ then
  1069. insertnode:=insertnode(newnode,currnode^.left)
  1070. else
  1071. begin
  1072. if replace_existing and
  1073. assigned(currnode) then
  1074. begin
  1075. newnode^.left:=currnode^.left;
  1076. newnode^.right:=currnode^.right;
  1077. currnode:=newnode;
  1078. insertnode:=newnode;
  1079. end
  1080. else
  1081. insertnode:=currnode;
  1082. end;
  1083. end;
  1084. end;
  1085. procedure tdictionary.inserttree(currtree,currroot:Pnamedindexobject);
  1086. begin
  1087. if assigned(currtree) then
  1088. begin
  1089. inserttree(currtree^.left,currroot);
  1090. inserttree(currtree^.right,currroot);
  1091. currtree^.right:=nil;
  1092. currtree^.left:=nil;
  1093. insertnode(currtree,currroot);
  1094. end;
  1095. end;
  1096. function tdictionary.rename(const olds,news : string):Pnamedindexobject;
  1097. var
  1098. spdval : longint;
  1099. lasthp,
  1100. hp,hp2,hp3 : Pnamedindexobject;
  1101. begin
  1102. spdval:=getspeedvalue(olds);
  1103. if assigned(hasharray) then
  1104. hp:=hasharray^[spdval mod hasharraysize]
  1105. else
  1106. hp:=root;
  1107. lasthp:=nil;
  1108. while assigned(hp) do
  1109. begin
  1110. if spdval>hp^.speedvalue then
  1111. begin
  1112. lasthp:=hp;
  1113. hp:=hp^.left
  1114. end
  1115. else
  1116. if spdval<hp^.speedvalue then
  1117. begin
  1118. lasthp:=hp;
  1119. hp:=hp^.right
  1120. end
  1121. else
  1122. begin
  1123. if (hp^.name=olds) then
  1124. begin
  1125. { get in hp2 the replacer for the root or hasharr }
  1126. hp2:=hp^.left;
  1127. hp3:=hp^.right;
  1128. if not assigned(hp2) then
  1129. begin
  1130. hp2:=hp^.right;
  1131. hp3:=hp^.left;
  1132. end;
  1133. { remove entry from the tree }
  1134. if assigned(lasthp) then
  1135. begin
  1136. if lasthp^.left=hp then
  1137. lasthp^.left:=hp2
  1138. else
  1139. lasthp^.right:=hp2;
  1140. end
  1141. else
  1142. begin
  1143. if assigned(hasharray) then
  1144. hasharray^[spdval mod hasharraysize]:=hp2
  1145. else
  1146. root:=hp2;
  1147. end;
  1148. { reinsert the hp3 in the tree from hp2 }
  1149. inserttree(hp3,hp2);
  1150. { reset node with new values }
  1151. stringdispose(hp^._name);
  1152. hp^._name:=stringdup(news);
  1153. hp^.speedvalue:=getspeedvalue(news);
  1154. hp^.left:=nil;
  1155. hp^.right:=nil;
  1156. { reinsert }
  1157. if assigned(hasharray) then
  1158. rename:=insertnode(hp,hasharray^[hp^.speedvalue mod hasharraysize])
  1159. else
  1160. rename:=insertnode(hp,root);
  1161. exit;
  1162. end
  1163. else
  1164. if olds>hp^.name then
  1165. begin
  1166. lasthp:=hp;
  1167. hp:=hp^.left
  1168. end
  1169. else
  1170. begin
  1171. lasthp:=hp;
  1172. hp:=hp^.right;
  1173. end;
  1174. end;
  1175. end;
  1176. end;
  1177. function Tdictionary.search(const s:string):Pnamedindexobject;
  1178. begin
  1179. search:=speedsearch(s,getspeedvalue(s));
  1180. end;
  1181. function Tdictionary.speedsearch(const s:string;speedvalue:longint):Pnamedindexobject;
  1182. var
  1183. newnode:Pnamedindexobject;
  1184. begin
  1185. if assigned(hasharray) then
  1186. newnode:=hasharray^[speedvalue mod hasharraysize]
  1187. else
  1188. newnode:=root;
  1189. while assigned(newnode) do
  1190. begin
  1191. if speedvalue>newnode^.speedvalue then
  1192. newnode:=newnode^.left
  1193. else
  1194. if speedvalue<newnode^.speedvalue then
  1195. newnode:=newnode^.right
  1196. else
  1197. begin
  1198. if (newnode^._name^=s) then
  1199. begin
  1200. speedsearch:=newnode;
  1201. exit;
  1202. end
  1203. else
  1204. if s>newnode^._name^ then
  1205. newnode:=newnode^.left
  1206. else
  1207. newnode:=newnode^.right;
  1208. end;
  1209. end;
  1210. speedsearch:=nil;
  1211. end;
  1212. {****************************************************************************
  1213. tsinglelist
  1214. ****************************************************************************}
  1215. constructor tsinglelist.init;
  1216. begin
  1217. first:=nil;
  1218. last:=nil;
  1219. end;
  1220. destructor tsinglelist.done;
  1221. begin
  1222. end;
  1223. procedure tsinglelist.reset;
  1224. begin
  1225. first:=nil;
  1226. last:=nil;
  1227. end;
  1228. procedure tsinglelist.clear;
  1229. var
  1230. hp,hp2 : pnamedindexobject;
  1231. begin
  1232. hp:=first;
  1233. while assigned(hp) do
  1234. begin
  1235. hp2:=hp;
  1236. hp:=hp^.listnext;
  1237. dispose(hp2,done);
  1238. end;
  1239. first:=nil;
  1240. last:=nil;
  1241. end;
  1242. procedure tsinglelist.insert(p:Pnamedindexobject);
  1243. begin
  1244. if not assigned(first) then
  1245. first:=p
  1246. else
  1247. last^.listnext:=p;
  1248. last:=p;
  1249. p^.listnext:=nil;
  1250. end;
  1251. {****************************************************************************
  1252. tindexarray
  1253. ****************************************************************************}
  1254. constructor tindexarray.init(Agrowsize:longint);
  1255. begin
  1256. growsize:=Agrowsize;
  1257. size:=0;
  1258. count:=0;
  1259. data:=nil;
  1260. first:=nil;
  1261. noclear:=false;
  1262. end;
  1263. destructor tindexarray.done;
  1264. begin
  1265. if assigned(data) then
  1266. begin
  1267. if not noclear then
  1268. clear;
  1269. freemem(data,size*4);
  1270. data:=nil;
  1271. end;
  1272. end;
  1273. function tindexarray.search(nr:longint):Pnamedindexobject;
  1274. begin
  1275. if nr<=count then
  1276. search:=data^[nr]
  1277. else
  1278. search:=nil;
  1279. end;
  1280. procedure tindexarray.clear;
  1281. var
  1282. i : longint;
  1283. begin
  1284. for i:=1 to count do
  1285. if assigned(data^[i]) then
  1286. begin
  1287. dispose(data^[i],done);
  1288. data^[i]:=nil;
  1289. end;
  1290. count:=0;
  1291. first:=nil;
  1292. end;
  1293. procedure tindexarray.foreach(proc2call : Tnamedindexcallback);
  1294. var
  1295. i : longint;
  1296. begin
  1297. for i:=1 to count do
  1298. if assigned(data^[i]) then
  1299. proc2call(data^[i]);
  1300. end;
  1301. procedure tindexarray.grow(gsize:longint);
  1302. var
  1303. osize : longint;
  1304. begin
  1305. osize:=size;
  1306. inc(size,gsize);
  1307. reallocmem(data,size*4);
  1308. fillchar(data^[osize+1],gsize*4,0);
  1309. end;
  1310. procedure tindexarray.deleteindex(p:Pnamedindexobject);
  1311. var
  1312. i : longint;
  1313. begin
  1314. i:=p^.indexnr;
  1315. { update counter }
  1316. if i=count then
  1317. dec(count);
  1318. { update linked list }
  1319. while (i>0) do
  1320. begin
  1321. dec(i);
  1322. if (i>0) and assigned(data^[i]) then
  1323. begin
  1324. data^[i]^.indexnext:=data^[p^.indexnr]^.indexnext;
  1325. break;
  1326. end;
  1327. end;
  1328. if i=0 then
  1329. first:=p^.indexnext;
  1330. data^[p^.indexnr]:=nil;
  1331. { clear entry }
  1332. p^.indexnr:=-1;
  1333. p^.indexnext:=nil;
  1334. end;
  1335. procedure tindexarray.delete(var p:Pnamedindexobject);
  1336. begin
  1337. deleteindex(p);
  1338. dispose(p,done);
  1339. p:=nil;
  1340. end;
  1341. procedure tindexarray.insert(p:Pnamedindexobject);
  1342. var
  1343. i : longint;
  1344. begin
  1345. if p^.indexnr=-1 then
  1346. begin
  1347. inc(count);
  1348. p^.indexnr:=count;
  1349. end;
  1350. if p^.indexnr>count then
  1351. count:=p^.indexnr;
  1352. if count>size then
  1353. grow(((count div growsize)+1)*growsize);
  1354. {$ifdef Delphi}
  1355. Assert(not assigned(data^[p^.indexnr]) or (p=data^[p^.indexnr]));
  1356. {$endif}
  1357. data^[p^.indexnr]:=p;
  1358. { update linked list backward }
  1359. i:=p^.indexnr;
  1360. while (i>0) do
  1361. begin
  1362. dec(i);
  1363. if (i>0) and assigned(data^[i]) then
  1364. begin
  1365. data^[i]^.indexnext:=p;
  1366. break;
  1367. end;
  1368. end;
  1369. if i=0 then
  1370. first:=p;
  1371. { update linked list forward }
  1372. i:=p^.indexnr;
  1373. while (i<=count) do
  1374. begin
  1375. inc(i);
  1376. if (i<=count) and assigned(data^[i]) then
  1377. begin
  1378. p^.indexnext:=data^[i];
  1379. exit;
  1380. end;
  1381. end;
  1382. if i>count then
  1383. p^.indexnext:=nil;
  1384. end;
  1385. end.
  1386. {
  1387. $Log$
  1388. Revision 1.21 2000-12-24 12:25:31 peter
  1389. + cstreams unit
  1390. * dynamicarray object to class
  1391. Revision 1.19 2000/11/12 22:20:37 peter
  1392. * create generic toutputsection for binary writers
  1393. Revision 1.18 2000/11/04 14:25:19 florian
  1394. + merged Attila's changes for interfaces, not tested yet
  1395. Revision 1.17 2000/11/03 19:41:06 jonas
  1396. * fixed bug in tdynamicarray.align (merged)
  1397. Revision 1.16 2000/10/31 22:02:46 peter
  1398. * symtable splitted, no real code changes
  1399. Revision 1.15 2000/10/14 10:14:46 peter
  1400. * moehrendorf oct 2000 rewrite
  1401. Revision 1.14 2000/09/24 21:19:50 peter
  1402. * delphi compile fixes
  1403. Revision 1.13 2000/09/24 15:06:12 peter
  1404. * use defines.inc
  1405. Revision 1.12 2000/08/27 20:19:38 peter
  1406. * store strings with case in ppu, when an internal symbol is created
  1407. a '$' is prefixed so it's not automatic uppercased
  1408. Revision 1.11 2000/08/27 16:11:50 peter
  1409. * moved some util functions from globals,cobjects to cutils
  1410. * splitted files into finput,fmodule
  1411. Revision 1.10 2000/08/19 18:44:27 peter
  1412. * new tdynamicarray implementation using blocks instead of
  1413. reallocmem (merged)
  1414. Revision 1.9 2000/08/16 18:33:53 peter
  1415. * splitted namedobjectitem.next into indexnext and listnext so it
  1416. can be used in both lists
  1417. * don't allow "word = word" type definitions (merged)
  1418. Revision 1.8 2000/08/13 08:41:57 peter
  1419. * fixed typo in tsinglelist.clear (merged)
  1420. Revision 1.7 2000/08/12 15:34:22 peter
  1421. + usedasmsymbollist to check and reset only the used symbols (merged)
  1422. Revision 1.6 2000/08/10 12:20:44 jonas
  1423. * reallocmem is now also used under Delphi (merged from fixes branch)
  1424. Revision 1.5 2000/08/09 12:09:45 jonas
  1425. * tidexarray and tdynamicarray now use reallocmem() under FPC for
  1426. growing (merged from fixes branch)
  1427. Revision 1.4 2000/08/06 19:42:40 peter
  1428. * removed note
  1429. Revision 1.3 2000/08/02 19:49:58 peter
  1430. * first things for default parameters
  1431. Revision 1.2 2000/07/13 11:32:38 michael
  1432. + removed logs
  1433. }