<> <> <> <> <> <> <> <> <> <<>> DIRECTORY Basics USING [CompareCard, CompareINT, Comparison], Rope USING [AppendChars, InlineSize, ROPE, Text], RopeReader USING [Body, Get, GetIndex, GetRope, MaxLen, Mode, ReadChar, Ref, SetPosition]; RopeReaderImpl: CEDAR MONITOR IMPORTS Basics, Rope, RopeReader EXPORTS RopeReader = BEGIN OPEN RopeReader; ROPE: TYPE = Rope.ROPE; Text: TYPE = Rope.Text; ReadOffEnd: PUBLIC ERROR = CODE; ReadChar: PUBLIC PROC [reader: Ref, mode: Mode] RETURNS [char: CHAR] = { rope: ROPE ~ reader.rope; -- the rope being read size: INT ~ rope.InlineSize[]; -- size of the rope index: INT ~ reader.index+reader.current; -- index of next char that Get would read text: REF TEXT ~ reader.text; -- text buffer length: NAT _ text.maxLength; -- number of chars to be read into buffer forward: BOOL ~ SELECT mode FROM get, peek => TRUE, backwards, peekbackwards => FALSE, ENDCASE => ERROR; inBounds: BOOL ~ IF forward THEN index IN[0..size) ELSE index IN(0..size]; IF NOT inBounds THEN { IF reader.charForEndOfRope THEN RETURN[reader.endChar] ELSE ERROR ReadOffEnd; }; IF forward THEN { rem: INT ~ size-index; IF rem { reader.current _ i+1; RETURN[text[i]] }; backwards => { RETURN[text[reader.current _ i-1]] }; peek => { RETURN[text[i]] }; peekbackwards => { RETURN[text[i-1]] }; ENDCASE => ERROR; } ELSE ERROR; }; EqSubstrs: PUBLIC PROC [r1, r2: ROPE, start1, start2, len: INT, rdr1, rdr2: Ref _ NIL] RETURNS [eq: BOOL] = { <> <> free1, free2: BOOL _ FALSE; size1: INT _ Rope.InlineSize[r1]; size2: INT _ Rope.InlineSize[r2]; start1 _ MIN[start1, size1]; start2 _ MIN[start2, size2]; IF len=MaxLen THEN { IF (len _ size1-start1) # size2-start2 THEN RETURN [FALSE] } ELSE IF start1+len > size1 THEN RETURN [FALSE] ELSE IF start2+len > size2 THEN RETURN [FALSE]; IF rdr1 = NIL THEN { rdr1 _ GetRopeReader[]; free1 _ TRUE }; IF rdr2 = NIL THEN { rdr2 _ GetRopeReader[]; free2 _ TRUE }; SetPosition[rdr1, r1, start1]; SetPosition[rdr2, r2, start2]; eq _ TRUE; WHILE len > 0 DO num: NAT _ NAT.LAST; -- loop on NAT instead of INT IF len NULL; ENDLOOP; IF free1 THEN FreeRopeReader[rdr1]; IF free2 THEN FreeRopeReader[rdr2]; }; CompareSubstrs: PUBLIC PROC [r1, r2: ROPE, start1, len1, start2, len2: INT, rdr1, rdr2: Ref _ NIL, case: BOOL _ TRUE] RETURNS [result: Basics.Comparison] = { <> <> size1: INT _ Rope.InlineSize[r1]; size2: INT _ Rope.InlineSize[r2]; rem, rem1, rem2: INT; free1, free2: BOOL _ FALSE; rem1 _ IF start1 > size1 THEN 0 ELSE size1-start1; rem2 _ IF start2 > size2 THEN 0 ELSE size2-start2; IF rdr1 = NIL THEN { rdr1 _ GetRopeReader[]; free1 _ TRUE }; IF rdr2 = NIL THEN { rdr2 _ GetRopeReader[]; free2 _ TRUE }; len1 _ MIN[len1, rem1]; len2 _ MIN[len2, rem2]; rem _ MIN[len1, len2]; SetPosition[rdr1, r1, start1]; SetPosition[rdr2, r2, start2]; result _ equal; WHILE rem > 0 DO num: NAT _ NAT.LAST; IF rem> IF LOOPHOLE[c1-'A, CARDINAL] <= ('Z-'A) THEN c1 _ LOOPHOLE[LOOPHOLE[c1, CARDINAL] + ('a-'A), CHAR]; IF LOOPHOLE[c2-'A, CARDINAL] <= ('Z-'A) THEN c2 _ LOOPHOLE[LOOPHOLE[c2, CARDINAL] + ('a-'A), CHAR]; }; IF c1 # c2 THEN { result _ Basics.CompareCard[LOOPHOLE[c1, CARDINAL], LOOPHOLE[c2, CARDINAL]]; GO TO Finis; }; ENDLOOP; REPEAT Finis => NULL; ENDLOOP; IF free1 THEN FreeRopeReader[rdr1]; IF free2 THEN FreeRopeReader[rdr2]; IF result # equal THEN RETURN; -- if a character differerence, then return it RETURN [Basics.CompareINT[len1, len2]]; -- if equal so far, the length determines }; <<***** rope reader cache>> defaultSize: NAT _ 200; roperdr1: Ref _ NIL; roperdr2: Ref _ NIL; roperdr3: Ref _ NIL; SetDefaultSize: PUBLIC ENTRY PROC [size: NAT] = { defaultSize _ size; roperdr1 _ roperdr2 _ roperdr3 _ NIL; }; Create: PUBLIC PROC [size: NAT _ 0] RETURNS [Ref] = { IF size=0 THEN size _ defaultSize; RETURN[NEW[Body _ [text: NEW[TEXT[size]]]]]; }; GetRopeReader: PUBLIC ENTRY PROC RETURNS [reader: Ref] = { SELECT Ref.NIL FROM # roperdr3 => { reader _ roperdr3; roperdr3 _ NIL }; # roperdr2 => { reader _ roperdr2; roperdr2 _ NIL }; # roperdr1 => { reader _ roperdr1; roperdr1 _ NIL }; ENDCASE => reader _ Create[]; }; FreeRopeReader: PUBLIC ENTRY PROC [reader: Ref] = { SetPosition[reader, NIL]; IF reader.text.maxLength#defaultSize THEN RETURN; reader.charForEndOfRope _ FALSE; IF roperdr3 = reader OR roperdr2 = reader OR roperdr1 = reader THEN ERROR; SELECT Ref.NIL FROM roperdr3 => roperdr3 _ reader; roperdr2 => roperdr2 _ reader; roperdr1 => roperdr1 _ reader; ENDCASE => NULL; }; END.