Copyright (C) 1994, Digital Equipment Corp.This module is very similar to the WrMove module, so we will list its code with only a few comments.
MODULEFastGetChar and GetChar are identical except that GetChar acquires and releases the lock while FastGetChar assumes it is already held.RdMove EXPORTSRd ,RdClass ,UnsafeRd ; IMPORT Thread; FROM Thread IMPORT Alerted; REVEAL Private = Thread.Mutex BRANDED OBJECT END;
It is invariant that for a closed reader rd
, rd.buff = NIL
and
rd.lo = rd.hi
. Therefore the check that rd
is ready need
not inspect rd.closed
on the fast path.
<*INLINE*> PROCEDUREEOF and FastEOF are identical except that EOF acquires and releases the reader lock while FastEOF assumes it is already held.GetChar (rd: T): CHAR RAISES {EndOfFile, Failure, Alerted} = VAR res: CHAR; BEGIN LOCK rd DO IF rd.cur = rd.hi THEN DoSeek(rd) END; res := rd.buff[rd.st + (rd.cur - rd.lo)]; INC(rd.cur); RETURN res END END GetChar; <*INLINE*> PROCEDUREFastGetChar (rd: T): CHAR RAISES {EndOfFile, Failure, Alerted} = (* rd is locked *) VAR res: CHAR; BEGIN IF rd.cur = rd.hi THEN DoSeek(rd) END; res := rd.buff[rd.st + (rd.cur - rd.lo)]; INC(rd.cur); RETURN res END FastGetChar; PROCEDUREDoSeek (rd: T) RAISES {EndOfFile, Failure, Alerted} = BEGIN (* rd.cur = rd.hi here *) IF rd.closed THEN Die() END; IF rd.seek(rd.cur, FALSE) = SeekResult.Eof THEN RAISE EndOfFile END END DoSeek; PROCEDUREGetSub (rd: T; VAR (*out*) str: ARRAY OF CHAR): CARDINAL RAISES {Failure, Alerted} = BEGIN LOCK rd DO IF rd.closed THEN Die() END; RETURN rd.getSub(str) END END GetSub; PROCEDUREFastGetSub (rd: T; VAR (*out*) str: ARRAY OF CHAR): CARDINAL RAISES {Failure, Alerted} = BEGIN IF rd.closed THEN Die() END; RETURN rd.getSub(str) END FastGetSub; PROCEDUREGetSubDefault (rd: T; VAR (*out*) str: ARRAY OF CHAR): CARDINAL RAISES {Failure, Alerted} = VAR i := 0; BEGIN LOOP (* i chars have been read into str *) IF i = NUMBER(str) THEN EXIT END; IF rd.cur = rd.hi THEN IF rd.seek(rd.cur, FALSE) = SeekResult.Eof THEN EXIT END END; (* rd.lo <= rd.cur < rd.hi *) VAR n := MIN(rd.hi - rd.cur, NUMBER(str) - i); BEGIN SUBARRAY(str, i, n) := SUBARRAY(rd.buff^, rd.cur - rd.lo + rd.st, n); INC(i, n); INC(rd.cur, n) END END; RETURN i END GetSubDefault;
<*INLINE*> PROCEDUREEOF (rd: T): BOOLEAN RAISES {Failure, Alerted} = (* rd is unlocked *) BEGIN LOCK rd DO IF rd.cur # rd.hi THEN RETURN FALSE ELSE IF rd.closed THEN Die() END; RETURN rd.seek(rd.cur, FALSE) = SeekResult.Eof END END END EOF; <*INLINE*> PROCEDUREFastEOF (rd: T): BOOLEAN RAISES {Failure, Alerted} = BEGIN (* rd is locked *) IF rd.cur # rd.hi THEN RETURN FALSE ELSE IF rd.closed THEN Die() END; RETURN rd.seek(rd.cur, FALSE) = SeekResult.Eof END END FastEOF; PROCEDUREUnGetChar (rd: T) RAISES {} = BEGIN LOCK rd DO FastUnGetChar (rd) END; END UnGetChar; PROCEDUREFastUnGetChar (rd: T) RAISES {} = BEGIN IF rd.closed OR rd.cur = rd.lo THEN Die() END; DEC(rd.cur) END FastUnGetChar; PROCEDURECharsReady (rd: T): CARDINAL RAISES {Failure} = <*FATAL Thread.Alerted*> BEGIN LOCK rd DO IF rd.cur = rd.hi THEN IF rd.closed THEN Die() END; IF rd.seek(rd.cur, TRUE) = SeekResult.Eof THEN RETURN 1 END END; RETURN rd.hi - rd.cur; END END CharsReady; PROCEDUREIndex (rd: T): CARDINAL RAISES {} = BEGIN LOCK rd DO IF rd.closed THEN Die() END; RETURN rd.cur END END Index; PROCEDURELength (rd: T): INTEGER RAISES {Failure, Alerted} = BEGIN LOCK rd DO IF rd.closed THEN Die() END; RETURN rd.length() END END Length; PROCEDURESeek (rd: T; n: CARDINAL) RAISES {Failure, Alerted} = BEGIN LOCK rd DO IF rd.closed OR NOT rd.seekable THEN Die() END; IF n < rd.lo OR n > rd.hi THEN EVAL rd.seek(n, FALSE); ELSE rd.cur := n; END END END Seek; PROCEDUREClose (rd: T) RAISES {Failure, Alerted} = BEGIN LOCK rd DO FastClose (rd); END; END Close; PROCEDUREFastClose (rd: T) RAISES {Failure, Alerted} = BEGIN IF NOT rd.closed THEN TRY rd.close() FINALLY rd.closed := TRUE; rd.cur := rd.hi; rd.lo := rd.hi; rd.buff := NIL END END END FastClose; PROCEDURELock (rd: T) RAISES {} = BEGIN Thread.Acquire (rd) END Lock; PROCEDUREUnlock (rd: T) RAISES {} = BEGIN Thread.Release (rd) END Unlock; PROCEDURELengthDefault (<*UNUSED*> rd: T): INTEGER RAISES {} = BEGIN <*NOWARN*> Die() END LengthDefault; PROCEDURECloseDefault (<*UNUSED*> rd: T) RAISES {} = BEGIN END CloseDefault; EXCEPTION FatalError; PROCEDUREDie () = <* FATAL FatalError *> BEGIN RAISE FatalError; END Die; BEGIN END RdMove.