DIRECTORY TextLooks, TextLooksSupport; RunReader: CEDAR DEFINITIONS IMPORTS TextLooksSupport SHARES TextLooks = BEGIN 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 ]; 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 { 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 { 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 { 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 { 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 { 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; Mode: PRIVATE TYPE = {get, backwards, peek, peekbackwards}; ReaderEscProc: TYPE = PROC [reader: Ref, mode: Mode] RETURNS [Offset, Looks]; ReadRun: PRIVATE ReaderEscProc; Equal: PROC [r1,r2: Runs, rdr1,rdr2: Ref] RETURNS [BOOLEAN] = INLINE { RETURN [EqSubstrs[r1,r2,0,0,LAST[Offset],rdr1,rdr2]] }; EqSubstrs: PROC [r1,r2: Runs, start1,start2,len: Offset, rdr1,rdr2: Ref] RETURNS [BOOLEAN]; GetRunReader: PROC RETURNS [reader: Ref]; FreeRunReader: PROC [reader: Ref]; Start: PROC; -- for initialization only END. \-- 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 -- ***** RunReader Declarations -- ***** RunReader Operations -- returns the current position of the reader -- get run, then increment reader location -- decrement reader location, then get run -- get run without incrementing reader location -- like Backwards, but doesn't change position -- 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 -- here are some operations making use of readers -- uses readers rdr1 and rdr2 to read runs r1 and r2 to test for equality -- 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 -- ***** Initialization Êa˜JšÏc™Jš&™&Jš6™6J˜š5™5š3™3Jš™J˜——Jš.™.J˜š&™&Jš.™.J˜—š5™5Jš.™.Jš-™-Jš3™3Jš*™*J˜—š3™3Jš.™.Jš$™$Jš&™&J˜—š-™-š8™8Jš+™+—šE™EJš*™*J˜——š.™.š1™1Jš0™0—šJ™JJš0™0J˜——š:™:š;™;Jš+™+—š=™=Jš4™4J˜——š4™4Jš<™