DIRECTORY Basics USING [bytesPerWord], RefText USING [BoundsFault, ErrorCode], Rope USING [AppendChars, InlineSize, ROPE]; RefTextImpl: CEDAR MONITOR IMPORTS RefText, Rope EXPORTS RefText = BEGIN ROPE: TYPE = Rope.ROPE; ReserveChars: PUBLIC PROC [to: REF TEXT, nChars: NAT] RETURNS [REF TEXT] = { newMinLength: INT = INT[to.length] + INT[nChars]; -- ERROR PointerFault if to=NIL IF newMinLength <= to.maxLength THEN RETURN [to]; IF newMinLength > NAT.LAST OR to.length > to.maxLength THEN RefText.BoundsFault[]; { expandBy: NAT = MAX[16, to.maxLength, nChars]; newLength: NAT = IF expandBy > NAT.LAST-to.maxLength THEN NAT.LAST ELSE expandBy+to.maxLength; newText: REF TEXT = NEW[TEXT[newLength]]; FOR i: NAT IN [0..to.length) DO newText[i] _ to[i] ENDLOOP; newText.length _ to.length; RETURN [newText]; } }; Append: PUBLIC PROC [to: REF TEXT, from: REF READONLY TEXT, start: NAT, len: NAT] RETURNS [REF TEXT] = TRUSTED { RETURN [AppendRope[to, LOOPHOLE[from], start, len]]; }; AppendChar: PUBLIC PROC [to: REF TEXT, from: CHAR] RETURNS [REF TEXT] = { IF to.length >= to.maxLength THEN { -- ERROR PointerFault if to=NIL to _ ReserveChars[to, 1]; }; to[to.length] _ from; to.length _ to.length + 1; RETURN [to]; }; AppendRope: PUBLIC PROC [to: REF TEXT, from: ROPE, start: INT, len: NAT] RETURNS [REF TEXT] = { rem: INT _ Rope.InlineSize[from] - start; IF start < 0 OR rem < 0 THEN RefText.BoundsFault[]; IF len < rem THEN rem _ len; IF rem > 0 THEN { to _ ReserveChars[to, rem]; [] _ Rope.AppendChars[to, from, start, rem]; }; RETURN [to]; }; New: PUBLIC PROC [nChars: NAT] RETURNS [REF TEXT] = { nChars _ nChars + (nChars MOD Basics.bytesPerWord); RETURN [NEW[TEXT[nChars]]]; }; TextIndex: TYPE = [0..1]; TextMaxLength: ARRAY TextIndex OF NAT = [100, 512]; NTextsToAllocate: ARRAY TextIndex OF NAT = [8, 2]; available: ARRAY TextIndex OF LIST OF REF TEXT _ ALL[NIL]; reserved: ARRAY TextIndex OF LIST OF REF TEXT _ ALL[NIL]; InterestingQuantity: TYPE = {obtainCalled, nCharsTooLarge, availEmpty}; Counts: ARRAY InterestingQuantity OF INT _ ALL[0]; Bump: INTERNAL PROC [q: InterestingQuantity] = INLINE { Counts[q] _ Counts[q] + 1 }; Error: PUBLIC ERROR [ec: RefText.ErrorCode] = CODE; ObtainScratch: PUBLIC ENTRY PROC [nChars: NAT] RETURNS [REF TEXT] = { i: TextIndex _ 0; avail: LIST OF REF TEXT; Bump[obtainCalled]; FOR i IN [0 .. LAST[TextIndex]] DO IF nChars <= TextMaxLength[i] THEN EXIT; REPEAT FINISHED => { Bump[nCharsTooLarge]; RETURN [New[nChars]] }; -- too large for pool ENDLOOP; IF (avail _ available[i].rest) = NIL THEN { r: LIST OF REF TEXT; Bump[availEmpty]; r _ reserved[i]; UNTIL r.rest.rest = NIL DO r _ r.rest ENDLOOP; avail _ r.rest; r.rest _ NIL; avail.first _ New[TextMaxLength[i]] }; available[i].rest _ avail.rest; avail.rest _ reserved[i].rest; reserved[i].rest _ avail; IF avail.first.length # 0 THEN RETURN WITH ERROR Error[clientModifiedReleasedText]; RETURN [avail.first] }; ReleaseScratch: PUBLIC ENTRY PROC [t: REF TEXT] = { i: TextIndex _ 0; r, l: LIST OF REF TEXT; IF t = NIL THEN RETURN; FOR i IN [0 .. LAST[TextIndex]] DO IF t.maxLength = TextMaxLength[i] THEN EXIT; REPEAT FINISHED => RETURN; -- no good for pool ENDLOOP; r _ reserved[i]; WHILE (l _ r.rest) # NIL DO IF l.first = t THEN { r.rest _ l.rest; l.rest _ available[i].rest; available[i].rest _ l; t.length _ 0; EXIT }; r _ l; ENDLOOP; }; InitializePool: PROC [] = { FOR i: TextIndex IN TextIndex DO reserved[i] _ CONS[NIL, NIL]; FOR j: NAT IN [0..NTextsToAllocate[i]] DO l: LIST OF REF TEXT _ CONS[NIL, available[i]]; available[i] _ l; ENDLOOP; ENDLOOP; FOR i: TextIndex IN TextIndex DO l: LIST OF REF TEXT _ available[i].rest; WHILE l # NIL DO l.first _ New[TextMaxLength[i]]; l _ l.rest; ENDLOOP; ENDLOOP; }; InitializePool[]; END. ²RefTextImpl.mesa, Operations on mutable garbage-collected strings (REF TEXT). Copyright c 1985 by Xerox Corporation. All rights reserved. MBrown on September 17, 1983 5:34 pm Russ Atkinson on January 31, 1985 5:07:58 pm PST Paul Rovner on August 8, 1983 11:39 am There are characters to append There are 10 overhead words per text (4 in the TEXT, 6 in the LIST), plus 6 overhead words per TextIndex value. Give last element of reserved[i] to the collector, allocate a new one, and put it in avail. Move first element of available[i] to front of reserved[i]. construct a list of NTextsToAllocate[i]+1 nodes. allocate a TEXT of maxLength TextMaxLength[i] for each node but the first. Êæ˜codešœM™MKšœ Ïmœ1™