RopeReaderMiscImpl.mesa
written by Bill Paxton, January 1981
Paxton, February 7, 1983 9:34 am
McGregor, June 10, 1982 3:18 pm
Maxwell, January 5, 1983 12:07 pm
Plass, March 7, 1983 2:27 pm
Russ Atkinson, November 10, 1983 5:05 pm
Paul Rovner, August 10, 1983 4:22 pm
DIRECTORY
Basics,
RopeReader,
RopeFrom,
Rope,
RopePrivate;
RopeReaderMiscImpl: CEDAR MONITOR
IMPORTS Basics, RopeReader, Rope, RopePrivate, RopeFrom
EXPORTS RopeReader
SHARES RopeReader, Rope =
BEGIN OPEN RopeReader, RopePrivate;
EqSubstrs: PUBLIC PROC [r1,r2: ROPE, start1,start2,len: Offset, rdr1,rdr2: Ref ← NIL]
RETURNS [eq: BOOLEAN] = {
-- uses readers rdr1 and rdr2 to read ropes r1 and r2 to test for equality
-- returns TRUE if r1 is same as len chars of r2 starting at start
free1, free2: BOOLEANFALSE;
size1: Offset ← Rope.InlineSize[r1];
size2: Offset ← 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 ← Short[MIN[len,LAST[NAT]]]; -- loop on NAT instead of Offset
len ← len-num;
THROUGH [0..num) DO
IF Get[rdr1]#Get[rdr2] THEN { eq ← FALSE; GOTO Finis };
ENDLOOP;
REPEAT Finis => NULL;
ENDLOOP;
IF free1 THEN FreeRopeReader[rdr1];
IF free2 THEN FreeRopeReader[rdr2];
};
CompareSubstrs: PUBLIC PROC [
r1, r2: ROPE, start1, len1, start2, len2: Offset,
rdr1, rdr2: Ref ← NIL, case: BOOLEANTRUE]
RETURNS [result: Basics.Comparison] = {
-- uses readers rdr1 and rdr2 to compare ropes r1 and r2
-- if ~case then all characters forced lowercase for comparison
size1: Offset ← Rope.InlineSize[r1];
size2: Offset ← Rope.InlineSize[r2];
rem, rem1, rem2: Offset;
free1, free2: BOOLEANFALSE;
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 ← Short[MIN[rem,LAST[NAT]]];
rem ← rem-num;
THROUGH [0..num) DO
c1: CHARACTER ← Get[rdr1];
c2: CHARACTER ← Get[rdr2];
IF ~case THEN {
special crock by RRA, verified as generating good code (generates few jumps)
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
};
-- implementation of ropes using character arrays
numCharsArrays: INT ← 0; -- number allocated
spacesFinalized: INT ← 0;
charsFinalized: INT ← 0;
CharsRope: PUBLIC SAFE PROC [chars: Chars] RETURNS [ROPE] = TRUSTED {
RETURN [Rope.MakeRope[LOOPHOLE[chars], charsPerArray, CharsFetch, CharsMap]];
};
CharsFetch: SAFE PROC [data: REF, index: Offset] RETURNS [c:CHAR] = TRUSTED {
WITH data SELECT FROM
x: Chars => RETURN[x[Short[index]]];
ENDCASE => ERROR Rope.NoRope };
CharsMap: SAFE PROC
[base: REF, start,len: Offset, action: PROC [CHAR] RETURNS [BOOLEAN]]
RETURNS [BOOLEAN] = TRUSTED {
WITH base SELECT FROM
x: Chars => {
st: NAT ← Short[start];
FOR i: NAT IN [st..st+Short[len]) DO
IF action[x[i]] THEN RETURN [TRUE];
ENDLOOP };
ENDCASE => ERROR Rope.NoRope;
RETURN [FALSE] };
-- ***** rope reader cache
Create: PUBLIC PROC RETURNS [Ref] = { RETURN[RopeFrom.qZone.NEW[Body]] };
roperdr1, roperdr2, roperdr3: Ref; -- shared rope readers
GetRopeReader: PUBLIC ENTRY PROC RETURNS [reader: Ref] = {
IF roperdr3 # NIL THEN { reader ← roperdr3; roperdr3 ← NIL }
ELSE IF roperdr2 # NIL THEN { reader ← roperdr2; roperdr2 ← NIL }
ELSE IF roperdr1 # NIL THEN { reader ← roperdr1; roperdr1 ← NIL }
ELSE reader ← Create[] };
FreeRopeReader: PUBLIC ENTRY PROC [reader: Ref] = {
SetPosition[reader, NIL];
reader.charForEndOfRope ← FALSE;
IF roperdr3 = reader OR roperdr2 = reader OR roperdr1 = reader THEN ERROR;
IF roperdr3 = NIL THEN roperdr3 ← reader
ELSE IF roperdr2 = NIL THEN roperdr2 ← reader
ELSE IF roperdr1 = NIL THEN roperdr1 ← reader };
-- ***** Initialization
StartRopeReaderMisc: PUBLIC PROC = TRUSTED {
};
END.