TABLE.MOD 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637
  1. (* ==================================================== *)
  2. (* Copyright (C) 1990-1992 Clarion Software Corporation *)
  3. (* ==================================================== *)
  4. IMPLEMENTATION MODULE Table;
  5. IMPORT Lib;
  6. FROM Storage IMPORT ALLOCATE, DEALLOCATE;
  7. CLASS IMPLEMENTATION Element;
  8. VIRTUAL PROCEDURE Compare( p : ElementPtr ) : INTEGER;
  9. (* It is an error not to supply an implementation of this
  10. method. The client MUST supply a method to compare
  11. 'THIS' with 'p'.
  12. *)
  13. BEGIN
  14. Lib.FatalError(' implemeted by client ');
  15. RETURN 0;
  16. END Compare;
  17. BEGIN
  18. END Element ;
  19. CLASS GenElem (Element) ;
  20. GenericData : CHAR;
  21. END GenElem;
  22. CLASS IMPLEMENTATION GenElem;
  23. BEGIN
  24. END GenElem;
  25. TYPE
  26. GenElemPtr = POINTER TO GenElem;
  27. (* The above definitions are a skeleton for all the
  28. implementation of the 'Element' CLASS. This enables
  29. the 'TABLE' class to successfully copy any client
  30. implementation of 'Element'
  31. *)
  32. CLASS IMPLEMENTATION TABLE;
  33. PROCEDURE Insert( VAR x : Element );
  34. (* Insert a new element 'x' in 'THIS' table *)
  35. PROCEDURE Search( VAR p : ElementPtr; VAR h : BOOLEAN);
  36. (* Searches a tree 'p' for the element 'x'. If it is found
  37. then the new value replaces the old. If 'x' is not
  38. in the tree, then 'x' becomes a new leaf of the tree.
  39. *)
  40. VAR
  41. p1 : ElementPtr;
  42. p2 : ElementPtr;
  43. BEGIN
  44. IF (p = NIL) THEN (* Create new leaf *)
  45. ALLOCATE(p,SIZE(x));
  46. Lib.Move(ADR(x),p,SIZE(x));
  47. p^.Bal := 0;
  48. p^.Left := NIL;
  49. p^.Right := NIL;
  50. h := TRUE; (* Tree requires balancing *)
  51. ELSE
  52. IF (x.Compare(p) < 0) THEN (* 'THIS' is < 'p' *)
  53. (* Search the 'Left' branch of 'p' recursively
  54. until 'x' is either found or created.
  55. *)
  56. Search(p^.Left,h);
  57. IF h THEN (* i.e. requires balancing *)
  58. CASE p^.Bal OF
  59. | 1 :
  60. p^.Bal := 0;
  61. h := FALSE;
  62. | 0 :
  63. p^.Bal := -1;
  64. | -1 :
  65. p1 := p^.Left;
  66. IF (p1^.Bal = -1) THEN
  67. p^.Left := p1^.Right;
  68. p1^.Right := p;
  69. p^.Bal := 0;
  70. p := p1;
  71. ELSE
  72. p2 := p1^.Right;
  73. p1^.Right := p2^.Left;
  74. p2^.Left := p1;
  75. p^.Left := p2^.Right;
  76. p2^.Right := p;
  77. IF (p2^.Bal = -1) THEN
  78. p^.Bal := 1;
  79. ELSE
  80. p^.Bal := 0;
  81. END;
  82. IF (p2^.Bal = 1) THEN
  83. p1^.Bal := -1;
  84. ELSE
  85. p1^.Bal := 0;
  86. END;
  87. p := p2;
  88. END;
  89. p^.Bal := 0;
  90. h := FALSE; (* Balancing done *)
  91. END (* CASE *);
  92. END (* of balancing 'Left' sub-tree *);
  93. ELSIF (x.Compare(p) > 0) THEN (* 'THIS' > 'p' *)
  94. (* Search the 'Right' branch of 'p' recursively
  95. until 'x' is either found or created.
  96. *)
  97. Search( p^.Right,h);
  98. IF h THEN (* i.e. tree needs balancing *)
  99. CASE p^.Bal OF
  100. | -1 :
  101. p^.Bal := 0;
  102. h := FALSE;
  103. | 0 :
  104. p^.Bal := 1;
  105. | 1 :
  106. p1 := p^.Right;
  107. IF (p1^.Bal = 1) THEN
  108. p^.Right := p1^.Left;
  109. p1^.Left := p;
  110. p^.Bal := 0;
  111. p := p1;
  112. ELSE
  113. p2 := p1^.Left;
  114. p1^.Left := p2^.Right;
  115. p2^.Right := p1;
  116. p^.Right := p2^.Left;
  117. p2^.Left := p;
  118. IF (p2^.Bal = 1) THEN
  119. p^.Bal := -1;
  120. ELSE
  121. p^.Bal := 0;
  122. END;
  123. IF (p2^.Bal = -1) THEN
  124. p1^.Bal := 1;
  125. ELSE
  126. p1^.Bal := 0;
  127. END;
  128. p := p2;
  129. END;
  130. p^.Bal := 0;
  131. h := FALSE; (* Tree balanced *)
  132. END (* CASE *);
  133. END (* Balancing 'Right' sub-tree *);
  134. ELSE (* 'THIS' and 'p' are the same *)
  135. h := FALSE;
  136. Lib.Move(ADR(GenElemPtr(ADR(x))^.GenericData),
  137. ADR(GenElemPtr(p)^.GenericData),
  138. SIZE(x)-VSIZE(Element.Bal));
  139. END (* Possible comaprison results *);
  140. END;
  141. END Search;
  142. VAR
  143. h : BOOLEAN;
  144. BEGIN
  145. IF (Root # NIL) AND (ADR(Root^.Compare) # ADR(x.Compare)) THEN
  146. (* All table elements must be homogeneous; i.e. they must be of
  147. the same CLASS
  148. *)
  149. Lib.FatalError('object not compatible with table');
  150. END;
  151. Search(Root,h);
  152. END Insert;
  153. PROCEDURE Find( VAR x : Element ) : BOOLEAN;
  154. (* Search for 'x' in 'THIS' tree; if 'x' is found in
  155. 'THIS' tree then the function returns 'TRUE' and 'x'
  156. is set to the mathing element. Otherwise the
  157. method returns 'FALSE'.
  158. *)
  159. PROCEDURE _Find( r : ElementPtr ) : ElementPtr;
  160. (* Implements the search algorithm *)
  161. BEGIN
  162. LOOP
  163. IF (r = NIL) THEN (* No match *)
  164. RETURN r;
  165. ELSIF (x.Compare(r) < 0) THEN (* 'THIS' < r *)
  166. r := r^.Left;
  167. ELSIF (x.Compare(r) > 0) THEN (* 'THIS' > r *)
  168. r := r^.Right;
  169. ELSE (* FOUND IT! *)
  170. RETURN r;
  171. END;
  172. END (* LOOP *);
  173. END _Find;
  174. VAR
  175. p : ElementPtr;
  176. BEGIN
  177. p := _Find(Root);
  178. IF (p # NIL) THEN (* Element Located *)
  179. Lib.Move(p,ADR(x),SIZE(x));
  180. RETURN TRUE;
  181. ELSE
  182. RETURN FALSE;
  183. END;
  184. END Find;
  185. PROCEDURE Delete( VAR x : Element );
  186. (* Locate the element 'x' in 'THIS' tree and delete it *)
  187. VAR
  188. q : ElementPtr;
  189. PROCEDURE r_Balance( VAR p : ElementPtr; VAR h : BOOLEAN);
  190. (* Blance a right sub-tree *)
  191. VAR
  192. p1 : ElementPtr;
  193. p2 : ElementPtr;
  194. b1 : BalanceFlag;
  195. b2 : BalanceFlag;
  196. BEGIN
  197. CASE p^.Bal OF
  198. | -1 :
  199. p^.Bal := 0;
  200. | 0 :
  201. p^.Bal := 1;
  202. h := FALSE;
  203. | 1 :
  204. p1 := p^.Right;
  205. b1 := p1^.Bal;
  206. IF (b1 >= 0) THEN
  207. p^.Right := p1^.Left;
  208. p1^.Left := p;
  209. IF (b1 = 0) THEN
  210. p^.Bal := 1;
  211. p1^.Bal := -1;
  212. h := FALSE
  213. ELSE
  214. p^.Bal := 0;
  215. p1^.Bal := 0;
  216. END;
  217. p := p1;
  218. ELSE
  219. p2 := p1^.Left;
  220. b2 := p2^.Bal;
  221. p1^.Left := p2^.Right;
  222. p2^.Right := p1;
  223. p^.Right := p2^.Left;
  224. p2^.Left := p;
  225. IF (b2 = 1) THEN
  226. p^.Bal := -1;
  227. ELSE
  228. p^.Bal := 0;
  229. END;
  230. IF (b2 = -1) THEN
  231. p1^.Bal := 1;
  232. ELSE
  233. p1^.Bal := 0;
  234. END;
  235. p := p2;
  236. p2^.Bal := 0;
  237. END;
  238. END (* CASE *);
  239. END r_Balance;
  240. PROCEDURE l_Balance( VAR p : ElementPtr; VAR h : BOOLEAN);
  241. (* Balance a left sub-tree *)
  242. VAR
  243. p1 : ElementPtr;
  244. p2 : ElementPtr;
  245. b1 : BalanceFlag;
  246. b2 : BalanceFlag;
  247. BEGIN
  248. CASE p^.Bal OF
  249. | 1 :
  250. p^.Bal := 0;
  251. | 0 :
  252. p^.Bal := -1;
  253. h := FALSE;
  254. | -1 :
  255. p1 := p^.Left;
  256. b1 := p1^.Bal;
  257. IF (b1 <= 0) THEN
  258. p^.Left := p1^.Right;
  259. p1^.Right := p;
  260. IF (b1 = 0) THEN
  261. p^.Bal := -1;
  262. p1^.Bal := 1;
  263. h := FALSE
  264. ELSE
  265. p^.Bal := 0;
  266. p1^.Bal := 0;
  267. END;
  268. p := p1;
  269. ELSE
  270. p2 := p1^.Right;
  271. b2 := p2^.Bal;
  272. p1^.Right := p2^.Left;
  273. p2^.Left := p1;
  274. p^.Left := p2^.Right;
  275. p2^.Right := p;
  276. IF (b2 = -1) THEN
  277. p^.Bal := 1;
  278. ELSE
  279. p^.Bal := 0;
  280. END;
  281. IF (b2 = 1) THEN
  282. p1^.Bal := -1;
  283. ELSE
  284. p1^.Bal := 0;
  285. END;
  286. p := p2;
  287. p2^.Bal := 0;
  288. END;
  289. END (* CASE *);
  290. END l_Balance;
  291. PROCEDURE DeleteLeaf( VAR r : ElementPtr; VAR h : BOOLEAN );
  292. (* Recursively search for extreme right-hand node of
  293. the sub-tree 'r' and move data into 'q'
  294. *)
  295. BEGIN
  296. IF (r^.Right # NIL) THEN
  297. DeleteLeaf(r^.Right,h);
  298. IF h THEN
  299. l_Balance(r,h);
  300. END;
  301. ELSE
  302. Lib.Move(ADR(GenElemPtr(r)^.GenericData),
  303. ADR(GenElemPtr(q)^.GenericData),
  304. SIZE(x)-VSIZE(Element.Bal));
  305. q := r;
  306. r := r^.Left;
  307. h := TRUE;
  308. END;
  309. END DeleteLeaf;
  310. PROCEDURE _Delete( VAR p : ElementPtr; VAR h : BOOLEAN );
  311. (* Main recursive deletion procedure *)
  312. BEGIN
  313. IF (p = NIL) THEN (* Not found *)
  314. h := FALSE;
  315. ELSIF (x.Compare(p) < 0) THEN (* 'THIS' < 'p' *)
  316. _Delete(p^.Left,h);
  317. IF h THEN
  318. r_Balance(p,h);
  319. END;
  320. ELSIF (x.Compare(p) > 0) THEN (* 'THIS' > 'p' *)
  321. _Delete(p^.Right,h);
  322. IF h THEN
  323. l_Balance(p,h);
  324. END;
  325. ELSE (* Found it! *)
  326. q := p;
  327. IF (q^.Right = NIL) THEN
  328. p := q^.Left;
  329. h := TRUE;
  330. ELSIF (q^.Left = NIL) THEN
  331. p := q^.Right;
  332. h := TRUE;
  333. ELSE
  334. DeleteLeaf(q^.Left,h);
  335. IF h THEN
  336. r_Balance(p,h);
  337. END;
  338. END;
  339. DISPOSE(q);
  340. END;
  341. END _Delete;
  342. VAR
  343. h : BOOLEAN;
  344. BEGIN
  345. IF (Root = NIL) THEN
  346. RETURN;
  347. END;
  348. IF (Root # NIL) AND (ADR(x.Compare) # ADR(Root^.Compare)) THEN
  349. (* 'x' is not the same type as tree members *)
  350. Lib.FatalError('object not compatible with table');
  351. END;
  352. _Delete(Root,h);
  353. END Delete;
  354. PROCEDURE Apply( p : Action );
  355. (* Apply a procedure to all table elements in order *)
  356. PROCEDURE ApplyToElement( s : ElementPtr );
  357. (* Apply 'p' to left sub-tree of s, then s, then the
  358. right sub-tree of s.
  359. *)
  360. BEGIN
  361. IF (s = NIL) THEN
  362. RETURN;
  363. ELSE
  364. ApplyToElement(s^.Left);
  365. p(s);
  366. ApplyToElement(s^.Right);
  367. END;
  368. END ApplyToElement;
  369. BEGIN
  370. ApplyToElement(Root);
  371. END Apply;
  372. PROCEDURE Init;
  373. (* Initialise a tree *)
  374. BEGIN
  375. Root := NIL;
  376. END Init;
  377. PROCEDURE Eq( t2 : TABLE ) : INTEGER;
  378. (* Compare 'THIS' to 't2'. Return values:
  379. <0 'THIS' is less than 't2'
  380. 0 'THIS' is equal to 't2'
  381. >0 'THIS' is greater than 't2'
  382. The trees are searched from the bottom up (i.e. in
  383. order) and the elements compared. The procedure
  384. returns immediately a difference is detected or
  385. when both trees are exhausted (and, therefore, they
  386. must be equal). This process is implemented iteratively
  387. rather than recursively.
  388. *)
  389. VAR
  390. S1,
  391. S2 : ARRAY [1..32] OF ElementPtr;
  392. r1,
  393. r2 : ElementPtr;
  394. sp1,
  395. sp2 : CARDINAL;
  396. res : INTEGER;
  397. BEGIN
  398. r1 := Root;
  399. r2 := t2.Root;
  400. IF (r1 # NIL) AND (r1 # r2) AND (ADR(r1^.Compare) # ADR(r2^.Compare)) THEN
  401. (* Both trees must contain the same sort of element *)
  402. Lib.FatalError(' not compareable ');
  403. END;
  404. sp1 := 0;
  405. sp2 := 0;
  406. LOOP
  407. WHILE (r1 # NIL) DO (* Build left edge array for 'THIS' *)
  408. INC(sp1);
  409. S1[sp1] := r1;
  410. r1 := r1^.Left;
  411. END;
  412. WHILE (r2 # NIL) DO (* Build left edge array for 't2' *)
  413. INC(sp2);
  414. S2[sp2] := r2;
  415. r2 := r2^.Left;
  416. END;
  417. IF (sp1 = 0) THEN (* No left sub-tree for 'THIS' *)
  418. IF (sp2 = 0) THEN (* No left sub-tree for 't2' *)
  419. RETURN 0; (* Implies they are equal *)
  420. ELSE
  421. RETURN -1; (* 'THIS' < 't2' *)
  422. END;
  423. ELSIF (sp2 = 0) THEN (* No left sub-tree for 't2' *)
  424. RETURN 1; (* 'THIS' > 't2' *)
  425. ELSE
  426. r1 := S1[sp1];
  427. DEC(sp1);
  428. r2 := S2[sp2];
  429. DEC(sp2);
  430. END;
  431. res := r1^.Compare(r2); (* Compare extreme left of both *)
  432. IF (res # 0) THEN (* These are different! *)
  433. RETURN res; (* Return how they are different *)
  434. END;
  435. r1 := r1^.Right;
  436. r2 := r2^.Right;
  437. END (* LOOP *);
  438. END Eq;
  439. PROCEDURE SubSet( t2 : TABLE ) : BOOLEAN;
  440. (* Are the elements of 'THIS' table a sub set of the elements
  441. of the table 't2'?
  442. The procedure scans scans the trees in order looking for
  443. an initial point of equality. Then 'THIS' is compared to
  444. this sub-tree of 't2' until either an element greater than
  445. the current 'THIS' element is found, or 'THIS' is exhuasted.
  446. The process is implemented iteratively rather than
  447. recursively.
  448. *)
  449. VAR
  450. S1,
  451. S2 : ARRAY [1..32] OF ElementPtr;
  452. r1,
  453. r2,
  454. cr : ElementPtr;
  455. sp1,
  456. sp2 : CARDINAL;
  457. res : INTEGER;
  458. BEGIN
  459. IF (Root # NIL) AND (t2.Root # Root) AND (ADR(Root^.Compare) # ADR(t2.Root^.Compare)) THEN
  460. (* Both trees must contain the same type of element *)
  461. Lib.FatalError('different types');
  462. END;
  463. r1 := Root;
  464. r2 := t2.Root;
  465. sp1 := 0;
  466. sp2 := 0;
  467. LOOP
  468. WHILE (r1 # NIL) DO
  469. INC(sp1);
  470. S1[sp1] := r1;
  471. r1 := r1^.Left;
  472. END;
  473. IF (sp1 = 0) THEN (* End of 'THIS' => is a sub-tree *)
  474. RETURN TRUE;
  475. END;
  476. r1 := S1[sp1];
  477. DEC(sp1);
  478. cr := r1;
  479. r1 := r1^.Right;
  480. LOOP
  481. WHILE (r2 # NIL) DO
  482. INC(sp2);
  483. S2[sp2] := r2;
  484. r2 := r2^.Left;
  485. END;
  486. IF (sp2 = 0) THEN (* End of 't2' => not a sub-tree *)
  487. RETURN FALSE;
  488. ELSE
  489. r2 := S2[sp2];
  490. DEC(sp2);
  491. END;
  492. res := cr^.Compare(r2);
  493. r2 := r2^.Right;
  494. IF (res < 0) THEN
  495. RETURN FALSE;
  496. ELSIF (res = 0) THEN
  497. EXIT;
  498. END;
  499. END (* LOOP *);
  500. END (* LOOP *);
  501. END SubSet;
  502. PROCEDURE Copy() : TABLE;
  503. (* Make a copy of 'THIS' *)
  504. PROCEDURE _Copy( r : ElementPtr ) : ElementPtr;
  505. (* Recursively generate a copy of 'r' *)
  506. VAR
  507. x : ElementPtr;
  508. BEGIN
  509. IF (r # NIL) THEN
  510. ALLOCATE(x,SIZE(r^));
  511. Lib.Move(r,x,SIZE(r^));
  512. x^.Left := _Copy(r^.Left);
  513. x^.Right := _Copy(r^.Right);
  514. RETURN x;
  515. ELSE
  516. RETURN r;
  517. END;
  518. END _Copy;
  519. VAR
  520. NewTree : TABLE;
  521. BEGIN
  522. NewTree.Root := _Copy(Root);
  523. RETURN NewTree;
  524. END Copy;
  525. PROCEDURE Incl( t2 : TABLE);
  526. (* Include 't2' in 'THIS' tree *)
  527. PROCEDURE _Incl( r : ElementPtr );
  528. (* Recursively insert 'r' into 'THIS' *)
  529. BEGIN
  530. IF (r # NIL) THEN
  531. _Incl(r^.Left);
  532. _Incl(r^.Right);
  533. Insert(r^);
  534. END;
  535. END _Incl;
  536. BEGIN
  537. IF (Root # NIL) AND (t2.Root # Root) AND (ADR(Root^.Compare) # ADR(t2.Root^.Compare)) THEN
  538. Lib.FatalError('different types');
  539. END;
  540. _Incl(t2.Root);
  541. END Incl;
  542. PROCEDURE Excl( t2 : TABLE);
  543. (* Exclude elements of 't2' from 'THIS' *)
  544. PROCEDURE _Excl( r: ElementPtr );
  545. (* Recursively exclude 'r' from 'THIS' *)
  546. BEGIN
  547. IF (r # NIL) THEN
  548. _Excl(r^.Left);
  549. _Excl(r^.Right);
  550. Delete(r^);
  551. END;
  552. END _Excl;
  553. BEGIN
  554. IF (Root # NIL) AND (t2.Root # Root) AND (ADR(Root^.Compare) # ADR(t2.Root^.Compare)) THEN
  555. Lib.FatalError('different types');
  556. END;
  557. _Excl(t2.Root);
  558. END Excl;
  559. PROCEDURE Empty() : BOOLEAN;
  560. (* Is 'THIS' empty? *)
  561. BEGIN
  562. RETURN (Root = NIL);
  563. END Empty;
  564. PROCEDURE Dispose;
  565. (* Dispose of entire tree *)
  566. PROCEDURE _Dispose( r : ElementPtr );
  567. (* Recursively dispose of each element of 'r' *)
  568. BEGIN
  569. IF (r # NIL) THEN
  570. _Dispose(r^.Left); (* Delete left sub-tree *)
  571. _Dispose(r^.Right); (* Delete right sub-tree *)
  572. DISPOSE(r);
  573. END;
  574. END _Dispose;
  575. BEGIN
  576. _Dispose(Root);
  577. END Dispose;
  578. BEGIN
  579. END TABLE ;
  580. END Table.
  581.