Last modified on Tue Jun 22 16:54:39 PDT 1993 by wobber modified on Mon May 31 06:25:00 PDT 1993 by swart modified on Mon Mar 09 13:46:38 PST 1992 by muller modified on Sat Feb 29 08:20:22 PST 1992 by kalsow
MODULEFastPutChar and PutChar are identical except that PutChar acquires and releases the lock while FastPutChar assumes it is already held.Wr EXPORTSWr ,WrClass ,UnsafeWr ; IMPORT Thread, Convert, Text, Word; 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; <*INLINE*> PROCEDUREPutWideChar (wr: T; ch: WIDECHAR) RAISES {Failure, Alerted} = BEGIN LOCK wr DO PutWC (wr, ch); IF NOT wr.buffered THEN wr.flush(); END; END; END PutWideChar; <*INLINE*> PROCEDUREFastPutWideChar (wr: T; ch: WIDECHAR) RAISES {Failure, Alerted} = BEGIN PutWC (wr, ch); IF NOT wr.buffered THEN wr.flush(); END; END FastPutWideChar; <*INLINE*> PROCEDUREPutWC (wr: T; ch: WIDECHAR) RAISES {Failure, Alerted} = VAR c1 := VAL (Word.Extract (ORD (ch), 0, 8), CHAR); c2 := VAL (Word.Extract (ORD (ch), 8, 8), CHAR); BEGIN IF wr.cur = wr.hi THEN DoSeek(wr) END; wr.buff[wr.st + wr.cur - wr.lo] := c1; INC(wr.cur); IF wr.cur = wr.hi THEN DoSeek(wr) END; wr.buff[wr.st + wr.cur - wr.lo] := c2; INC(wr.cur); END PutWC; 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 LOCK wr DO FastPutText (wr, t); END; END PutText; PROCEDUREFastPutText (wr: T; t: TEXT) RAISES {Failure, Alerted} = VAR len : CARDINAL := Text.Length (t); offset : CARDINAL := 0; buf : ARRAY [0..127] OF CHAR; BEGIN IF wr.closed THEN Die() END; WHILE offset < len DO Text.SetChars (buf, t, offset); wr.putString (SUBARRAY (buf, 0, MIN (len - offset, NUMBER (buf)))); INC (offset, NUMBER (buf)); END; IF NOT wr.buffered THEN wr.flush(); END; END FastPutText; PROCEDUREPutWideText (wr: T; t: TEXT) RAISES {Failure, Alerted} = BEGIN LOCK wr DO FastPutWideText (wr, t); END; END PutWideText; PROCEDUREFastPutWideText (wr: T; t: TEXT) RAISES {Failure, Alerted} = VAR len : CARDINAL := Text.Length (t); offset : CARDINAL := 0; buf : ARRAY [0..127] OF WIDECHAR; BEGIN IF wr.closed THEN Die() END; WHILE offset < len DO Text.SetWideChars (buf, t, offset); FOR i := 0 TO MIN (len - offset, NUMBER (buf)) - 1 DO PutWC (wr, buf[i]); END; INC (offset, NUMBER (buf)); END; IF NOT wr.buffered THEN wr.flush(); END; END FastPutWideText;
<*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; <*INLINE*> PROCEDUREPutWideString (wr: T; READONLY a: ARRAY OF WIDECHAR) RAISES {Failure, Alerted} = BEGIN LOCK wr DO FastPutWideString(wr, a); END; END PutWideString; <*INLINE*> PROCEDUREFastPutWideString (wr: T; READONLY a: ARRAY OF WIDECHAR) RAISES {Failure, Alerted} = BEGIN IF wr.closed THEN Die() END; FOR i := 0 TO LAST (a) DO PutWC(wr, a[i]); END; IF NOT wr.buffered THEN wr.flush(); END; END FastPutWideString; 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 Wr.