cclasses.pas 41 KB

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