RunReader.mesa; written by Bill Paxton, March 1981
last edit by McGregor, February 8, 1983 11:52 am
last edit by Bill Paxton, June 1, 1983 11:18 am
RunReader provides fast inline access to look runs
designed for speed in reading a sequence of runs
either forwards or backwards
supports looks as defined by TiogaLooks.Mesa
create a reader by RunReader.Create
reader: RunReader.Ref ← RunReader.Create[];
position it where you wanto to read by SetPosition
RunReader.SetPosition[reader, runs, index];
where runs is TiogaLooks runs to read from
and index is the initial position for the reader
you can reposition a reader at any time
read its current position in the following ways:
[runs, index] ← RunReader.Position[reader];
runs ← RunReader.GetRuns[reader];
index ← RunReader.GetIndex[reader];
to read in ascending order (left to right)
initialize position before first character to be read
for example, use 0 to start at beginning
then call Get which reads to the right and increments the position
[count, looks] ← RunReader.Get[reader];
to read in descending order (right to left)
initialize position after first run to be read
for example, use size of rope to start at end
then call Backwards which reads to the left and decrements the position
[count, looks] ← RunReader.Backwards[reader];
can also get a run without changing the reader position
to look at the next run that Get would return, call Peek
[count, looks] ← RunReader.Peek[reader];
to look at what Backwards would return, call PeekBackwards
[count, looks] ← RunReader.PeekBackwards[reader];
can intermix reading or peeking to left and right
don't need to reinitialize the reader to change direction
if read off either end, you will get an error
DIRECTORY
TiogaLooks, TiogaLooksSupport;
RunReader: CEDAR DEFINITIONS
IMPORTS TiogaLooksSupport =
BEGIN
***** RunReader Declarations
Base: TYPE = TiogaLooks.BaseRuns;
Looks: TYPE = TiogaLooks.Looks;
noLooks: Looks = TiogaLooks.noLooks;
Runs: TYPE = TiogaLooks.Runs;
Offset: TYPE = TiogaLooks.Offset;
NoMoreRuns: ERROR; -- if try to read off end
Ref: TYPE = REF Body;
Body: TYPE = PRIVATE RECORD [
current: NAT ← 0, -- index of current run
first: NAT ← 0, -- index of first run to read
after: NAT ← 0, -- index beyond last run to read
base: Base, -- current array of runs
changeLooks: BOOLEANFALSE, -- if need to change looks from base
remove, add: Looks ← noLooks, -- the change
runs: Runs ← NIL, -- runs that we are reading
index: Offset ← 0 -- index in runs
];
***** RunReader Operations
Create: PROC RETURNS [Ref];
SetPosition: PROC [reader: Ref, runs: Runs, index: Offset ← 0] =
INLINE {
IF runs # GetRuns[reader] OR index # GetIndex[reader] THEN
reader^ ← [0,0,0,NIL,FALSE,noLooks,noLooks,runs,index];
};
SetIndex: PROC [reader: Ref, index: Offset ← 0] = INLINE {
IF index # GetIndex[reader] THEN {
runs: Runs ← GetRuns[reader];
reader^ ← [0,0,0,NIL,FALSE,noLooks,noLooks,runs,index]}};
BackupIndex: PROC [reader: Ref, amount: Offset] = INLINE {
SetIndex[reader, GetIndex[reader]-amount] };
BumpIndex: PROC [reader: Ref, amount: Offset] = INLINE {
SetIndex[reader, GetIndex[reader]+amount] };
Position: PROC [reader: Ref]
RETURNS [runs: Runs, index: Offset] = INLINE {
returns the current position of the reader
RETURN [GetRuns[reader], GetIndex[reader]] };
GetRuns: PROC [reader: Ref]
RETURNS [runs: Runs] = INLINE { RETURN [reader.runs] };
GetIndex: PROC [reader: Ref] RETURNS [index: Offset];
ReaderProc: TYPE = PROC [reader: Ref] RETURNS [count: Offset, looks: Looks];
Get: ReaderProc = INLINE {
get run, then increment reader location
current: NAT;
base: Base;
IF (current←reader.current) >= reader.after THEN
{ [count, looks] ← ReadRun[reader, get]; RETURN };
reader.current ← current+1;
base ← reader.base;
count ← IF current=0 THEN base[0].after ELSE
base[current].after-base[current-1].after;
looks ← base[current].looks;
IF reader.changeLooks THEN
looks ← TiogaLooksSupport.ModifyLooks[looks,reader.remove,reader.add] };
Backwards: ReaderProc = INLINE {
decrement reader location, then get run
current: NAT;
base: Base;
IF (current←reader.current) <= reader.first THEN
{ [count, looks] ← ReadRun[reader, backwards]; RETURN };
base ← reader.base;
count ← IF (reader.current ← current ← current-1)=0 THEN base[0].after ELSE
base[current].after-base[current-1].after;
looks ← base[current].looks;
IF reader.changeLooks THEN
looks ← TiogaLooksSupport.ModifyLooks[looks,reader.remove,reader.add] };
Peek: ReaderProc = INLINE {
get run without incrementing reader location
current: NAT;
base: Base;
IF (current←reader.current) >= reader.after THEN
{ [count, looks] ← ReadRun[reader, peek]; RETURN };
base ← reader.base;
count ← IF current=0 THEN base[0].after ELSE
base[current].after-base[current-1].after;
looks ← base[current].looks;
IF reader.changeLooks THEN
looks ← TiogaLooksSupport.ModifyLooks[looks,reader.remove,reader.add] };
PeekBackwards: ReaderProc = INLINE {
like Backwards, but doesn't change position
current: NAT;
base: Base;
IF (current←reader.current) <= reader.first THEN
{ [count, looks] ← ReadRun[reader, backwards]; RETURN };
base ← reader.base;
count ← IF (current ← current-1)=0 THEN base[0].after ELSE
base[current].after-base[current-1].after;
looks ← base[current].looks;
IF reader.changeLooks THEN
looks ← TiogaLooksSupport.ModifyLooks[looks,reader.remove,reader.add] };
MergedGet: ReaderProc;
merges adjacent runs with same looks
regular Get may give same looks on successive calls
e.g., if Concat[A,B] produces in a concat-node
and the last run in A has the same looks as the first in B
Get will first return last run from A, then first from B
MergedGet will combine these into a single result1
Mode: PRIVATE TYPE = {get, backwards, peek, peekbackwards};
ReaderEscProc: TYPE = PROC [reader: Ref, mode: Mode] RETURNS [Offset, Looks];
ReadRun: PRIVATE ReaderEscProc;
here are some operations making use of readers
Equal: PROC [r1,r2: Runs, rdr1,rdr2: Ref] RETURNS [BOOLEAN] = INLINE {
uses readers rdr1 and rdr2 to read runs r1 and r2 to test for equality
RETURN [EqSubstrs[r1,r2,0,0,LAST[Offset],rdr1,rdr2]] };
EqSubstrs: PROC [r1,r2: Runs, start1,start2,len: Offset, rdr1,rdr2: Ref]
RETURNS [BOOLEAN];
uses readers rdr1 and rdr2 to read runs r1 and r2 to test for equality
returns TRUE if r1 starting at start1 is same as
len looks of r2 starting at start2
returns FALSE if not enough looks available in either
i.e., if start1+len > size[r1] or start2+len > size[r2]
the next routines provide caches of readers
so can avoid creating a lot of garbage
GetRunReader: PROC RETURNS [reader: Ref];
FreeRunReader: PROC [reader: Ref];
END.