<<-- LooksReader.mesa>> <<-- written by Bill Paxton, March 1981>> <<-- last edit by Bill Paxton, May 28, 1982 10:24 am>> <<-- LooksReader provides fast inline access to looks>> <<-- designed for speed in reading a sequence of looks>> <<-- either forwards or backwards>> <<-- supports looks as defined by TextLooks.Mesa>> <<-- create a reader by calling Create>> <<-- reader: LooksReader.Ref _ Create[];>> <<-- position it where you want to read by SetPosition>> <<-- LooksReader.SetPosition[reader, runs, index];>> <<-- where runs is TextLooks.Runs to read from>> <<-- and index is the initial position for the reader>> <<-- you can reposition a reader at any time>> <<-- read its position in the following ways:>> <<-- [runs, index] _ LooksReader.Position[reader];>> <<-- runs _ LooksReader.GetRuns[reader];>> <<-- index _ LooksReader.GetIndex[reader];>> <<-- to read in ascending order (left to right)>> <<-- initialize position before first looks to be read>> <<-- for example, use 0 to start at beginning>> <<-- then call Get which reads to the right and increments the position>> <<-- looks _ LooksReader.Get[reader];>> <<-- to read in descending order (right to left)>> <<-- initialize position after first looks to be read>> <<-- for example, use Size[runs] to start at end>> <<-- then call Backwards which reads to the left and decrements the position>> <<-- looks _ LooksReader.Backwards[reader];>> <<-- can also get looks without changing the reader position>> <<-- to look at the next looks that Get would return, call Peek>> <<-- looks _ LooksReader.Peek[reader];>> <<-- to look at what Backwards would return, call PeekBackwards>> <<-- looks _ LooksReader.PeekBackwards[reader];>> <<-- can intermix reading or peeking to left and right>> <<-- don't need to reinitialize the reader to change direction>> DIRECTORY TextLooks, RunReader; LooksReader: CEDAR DEFINITIONS IMPORTS RunReader = BEGIN Offset: TYPE = TextLooks.Offset; Looks: TYPE = TextLooks.Looks; noLooks: Looks = TextLooks.noLooks; Runs: TYPE = TextLooks.Runs; Ref: TYPE = REF Body; Body: TYPE = PRIVATE RECORD [ rem: NAT, -- remainder of current run len: NAT, -- length of current run looks: Looks, -- looks for current run runreader: RunReader.Ref -- reader for runs ]; Create: PROC [] RETURNS [Ref]; <<-- create a reader for chars and looks>> SetPosition: PROC [reader: Ref, runs: Runs, index: Offset _ 0] = INLINE { <<-- set position of reader>> reader.rem _ reader.len _ 0; RunReader.SetPosition[reader.runreader, runs, index] }; SetIndex: PROC [reader: Ref, index: Offset _ 0] = INLINE { reader.rem _ reader.len _ 0; RunReader.SetIndex[reader.runreader, 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] = <<-- return position of looks reader>> INLINE { RETURN [GetRuns[reader], GetIndex[reader]] }; GetRuns: PROC [reader: Ref] RETURNS [Runs] = INLINE { RETURN [RunReader.GetRuns[reader.runreader]] }; GetIndex: PROC [reader: Ref] RETURNS [index: Offset] = INLINE { RETURN [ RunReader.GetIndex[reader.runreader]-reader.rem]}; ReaderProc: TYPE = PROC [reader: Ref] RETURNS [Looks]; Get: ReaderProc = INLINE { <<-- get looks, then increment reader location>> rem: NAT; IF (rem_reader.rem) = 0 THEN { -- go to the next run len: Offset; [len, reader.looks] _ RunReader.Get[reader.runreader]; IF len > LAST[NAT] THEN { RunReader.BackupIndex[reader.runreader,len-LAST[NAT]]; len _ LAST[NAT] }; reader.len _ rem _ len}; reader.rem _ rem-1; RETURN[reader.looks]}; Backwards: ReaderProc = INLINE { <<-- decrement reader location, then get looks>> rem: NAT; IF (rem_reader.rem) >= reader.len THEN { -- go to the previous run len: Offset; [len, reader.looks] _ RunReader.Backwards[reader.runreader]; IF len > LAST[NAT] THEN { RunReader.BumpIndex[reader.runreader,len-LAST[NAT]]; len _ LAST[NAT] }; reader.len _ len; rem _ 0 }; reader.rem _ rem+1; RETURN[reader.looks]}; Peek: ReaderProc = INLINE { <<-- get looks without incrementing reader location>> looks: Looks; IF reader.rem = 0 THEN [,looks] _ RunReader.Peek[reader.runreader] ELSE looks _ reader.looks; RETURN [looks]}; PeekBackwards: ReaderProc = INLINE { <<-- like Backwards, but doesn't change position>> looks: Looks; IF reader.rem >= reader.len THEN [,looks] _ RunReader.PeekBackwards[reader.runreader] ELSE looks _ reader.looks; RETURN [looks]}; <<-- the following two routines implement a small cache of looks readers>> <<-- so can avoid creating a lot of garbage>> <<-- but don't use unless sure will not free more than once>> <<-- no harm if fail to free (garbage collector will get it)>> <<-- but chaos if free twice>> GetLooksReader: PROC RETURNS [Ref]; FreeLooksReader: PROC[Ref]; Start: PROC; -- for initialization only END.