Copyright (C) 1994, Digital Equipment Corp. MODULEFastPutChar and PutChar are identical except that PutChar acquires and releases the lock while FastPutChar assumes it is already held.WrMove EXPORTSWr ,WrClass ,UnsafeWr ; IMPORT Thread, Convert, Text, TextF; FROM Thread IMPORT Alerted; REVEAL Private = Thread.Mutex BRANDED OBJECT END;
It is invariant that for a closed writer wr
, wr.buff = NIL
and
wr.lo = wr.hi
. Therefore the check that wr
is ready need
not inspect wr.closed
on the fast path.
PROCEDUREPutString and FastPutString are identical except that PutString acquires and releases the lock while FastPutString assumes it is already held.Lock (wr: T) RAISES {} = BEGIN Thread.Acquire(wr); END Lock; PROCEDUREUnlock (wr: T) = BEGIN Thread.Release(wr) END Unlock; <*INLINE*> PROCEDUREPutChar (wr: T; ch: CHAR) RAISES {Failure, Alerted} = BEGIN LOCK wr DO IF wr.cur = wr.hi THEN DoSeek(wr) END; wr.buff[wr.st + wr.cur - wr.lo] := ch; INC(wr.cur); IF NOT wr.buffered THEN wr.flush(); END; END; END PutChar; <*INLINE*> PROCEDUREFastPutChar (wr: T; ch: CHAR) RAISES {Failure, Alerted} = BEGIN IF wr.cur = wr.hi THEN DoSeek(wr) END; wr.buff[wr.st + wr.cur - wr.lo] := ch; INC(wr.cur); IF NOT wr.buffered THEN wr.flush(); END; END FastPutChar; PROCEDUREDoSeek (wr: T) RAISES {Failure, Alerted} = BEGIN (* wr.cur = wr.hi here *) IF wr.closed THEN Die() END; wr.seek(wr.cur); END DoSeek; PROCEDUREPutText (wr: T; t: TEXT) RAISES {Failure, Alerted} = BEGIN PutString (wr, SUBARRAY (t^, 0, Text.Length (t))); END PutText; PROCEDUREFastPutText (wr:T; t: TEXT) RAISES {Failure, Alerted} = BEGIN FastPutString (wr, SUBARRAY (t^, 0, Text.Length (t))); END FastPutText;
<*INLINE*> PROCEDUREPutString (wr: T; READONLY a: ARRAY OF CHAR) RAISES {Failure, Alerted} = BEGIN LOCK wr DO IF wr.closed THEN Die() END; wr.putString(a); IF NOT wr.buffered THEN wr.flush(); END; END; END PutString; <*INLINE*> PROCEDUREFastPutString (wr: T; READONLY a: ARRAY OF CHAR) RAISES {Failure, Alerted} = BEGIN IF wr.closed THEN Die() END; wr.putString(a); IF NOT wr.buffered THEN wr.flush(); END; END FastPutString; PROCEDUREPutStringDefault (wr: T; READONLY a: ARRAY OF CHAR) RAISES {Failure, Alerted} = VAR start: CARDINAL := 0; l := NUMBER(a); BEGIN WHILE (l > 0) DO VAR n := MIN(wr.hi - wr.cur, l); BEGIN IF n > 0 THEN SUBARRAY(wr.buff^, wr.st + wr.cur - wr.lo, n) := SUBARRAY(a, start, n); INC(start, n); DEC(l, n); INC(wr.cur, n); END; END; IF l > 0 THEN wr.seek(wr.cur) END; END; END PutStringDefault; PROCEDUREFastPutInt (wr: T; n: INTEGER; base: Convert.Base := 10) RAISES {Failure, Alerted} = <*FATAL Convert.Failed*> VAR chars: ARRAY [0..BITSIZE(INTEGER) + 3] OF CHAR; size: INTEGER; BEGIN size := Convert.FromInt (chars, n, base); FastPutString (wr, SUBARRAY (chars, 0, size)); END FastPutInt; PROCEDUREFastPutReal (wr: T; r: REAL; p: CARDINAL := 6; s := Convert.Style.Mix) RAISES {Failure, Alerted} = <*FATAL Convert.Failed*> VAR chars: ARRAY [0..100] OF CHAR; size: INTEGER; BEGIN size := Convert.FromFloat (chars, r, p, s); FastPutString (wr, SUBARRAY (chars, 0, size)); END FastPutReal; PROCEDUREFastPutLongReal (wr: T; r: LONGREAL; p: CARDINAL := 6; s := Convert.Style.Mix) RAISES {Failure, Alerted} = <*FATAL Convert.Failed*> VAR chars: ARRAY [0..100] OF CHAR; size: INTEGER; BEGIN size := Convert.FromLongFloat (chars, r, p, s); FastPutString (wr, SUBARRAY (chars, 0, size)); END FastPutLongReal; PROCEDURESeek (wr: T; n: CARDINAL) RAISES {Failure, Alerted} = BEGIN LOCK wr DO IF wr.closed OR NOT wr.seekable THEN Die() END; wr.seek(n); END END Seek; PROCEDUREFlush (wr: T) RAISES {Failure, Alerted} = BEGIN LOCK wr DO IF wr.closed THEN Die() END; wr.flush(); END; END Flush; PROCEDUREIndex (wr: T): CARDINAL RAISES {} = BEGIN LOCK wr DO IF wr.closed THEN Die() END; RETURN wr.cur; END END Index; PROCEDURELength (wr: T): CARDINAL RAISES {Failure, Alerted} = BEGIN LOCK wr DO IF wr.closed THEN Die() END; RETURN wr.length (); END END Length; PROCEDUREClose (wr: T) RAISES {Failure, Alerted} = BEGIN LOCK wr DO FastClose (wr); END; END Close; PROCEDUREFastClose (wr: T) RAISES {Failure, Alerted} = BEGIN IF NOT wr.closed THEN TRY TRY wr.flush() FINALLY wr.close() END FINALLY wr.closed := TRUE; wr.cur := wr.hi; wr.lo := wr.hi; wr.buff := NIL END END END FastClose; PROCEDURESeekable (wr: T): BOOLEAN RAISES {} = BEGIN LOCK wr DO RETURN wr.seekable END END Seekable; PROCEDUREClosed (wr: T): BOOLEAN RAISES {} = BEGIN LOCK wr DO RETURN wr.closed; END END Closed; PROCEDUREBuffered (wr: T): BOOLEAN RAISES {} = BEGIN LOCK wr DO RETURN wr.buffered; END END Buffered; PROCEDURECloseDefault (<*UNUSED*> wr: T) RAISES {} = BEGIN END CloseDefault; PROCEDUREFlushDefault (<*UNUSED*> wr: T) RAISES {} = BEGIN END FlushDefault; PROCEDURELengthDefault (wr: T): CARDINAL RAISES {} = BEGIN RETURN wr.cur; END LengthDefault; EXCEPTION FatalError; PROCEDUREDie () = <* FATAL FatalError *> BEGIN RAISE FatalError; END Die; BEGIN END WrMove.