<<-- RunReader.mesa>> <<-- written by Bill Paxton, March 1981>> <<-- last edit by Bill Paxton, December 22, 1981 2:02 pm>> <<-- 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 TextLooks.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 TextLooks, TextLooksSupport; RunReader: CEDAR DEFINITIONS IMPORTS TextLooksSupport SHARES TextLooks = BEGIN <<-- ***** RunReader Declarations>> Base: TYPE = TextLooks.BaseRuns; Looks: TYPE = TextLooks.Looks; noLooks: Looks = TextLooks.noLooks; Runs: TYPE = TextLooks.Runs; Offset: TYPE = TextLooks.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: BOOLEAN _ FALSE, -- 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 _ TextLooksSupport.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 _ TextLooksSupport.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 _ TextLooksSupport.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 _ TextLooksSupport.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]; <<-- ***** Initialization>> Start: PROC; -- for initialization only END.