-- RefTextImpl.mesa, Operations on mutable garbage-collected strings (REF TEXT). -- MBrown on September 17, 1983 5:34 pm -- Russ Atkinson on June 7, 1982 6:01 pm -- Paul Rovner on August 8, 1983 11:39 am DIRECTORY RefText USING [BoundsFault, ErrorCode, InlineAppendChar], Rope USING [ROPE, Map]; 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] = { j: NAT _ to.length; -- ERROR PointerFault if to=NIL IF start > from.length OR j > to.maxLength THEN RefText.BoundsFault[]; len _ MIN[from.length-start, len]; IF len > to.maxLength-j THEN to _ ReserveChars[to, len]; FOR i: NAT IN [start..start+len) DO to[j] _ from[i]; j _ j + 1; ENDLOOP; to.length _ j; RETURN [to]; }; 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: NAT, len: NAT] RETURNS [REF TEXT] = { Put: PROC [c: CHAR] RETURNS [quit: BOOL] = { to _ RefText.InlineAppendChar[to, c]; RETURN [quit: FALSE] }; [] _ Rope.Map[base: from, start: start, len: len, action: Put]; RETURN [to]; }; New: PUBLIC PROC [nChars: NAT] RETURNS [REF TEXT] = { RETURN [NEW[TEXT[nChars]]] }; TextIndex: TYPE = [0..1]; TextMaxLength: ARRAY TextIndex OF NAT = [100, 512]; NTextsToAllocate: ARRAY TextIndex OF NAT = [8, 2]; -- There are 10 overhead words per text (4 in the TEXT, 6 in the LIST), plus --6 overhead words per TextIndex value. 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 { -- Give last element of reserved[i] to the collector, allocate a new one, and put it in avail. 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]] }; -- Move first element of available[i] to front of reserved[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]; -- construct a list of NTextsToAllocate[i]+1 nodes. 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 -- allocate a TEXT of maxLength TextMaxLength[i] for each node but the first. l: LIST OF REF TEXT _ available[i].rest; WHILE l # NIL DO l.first _ New[TextMaxLength[i]]; l _ l.rest; ENDLOOP; ENDLOOP; }; InitializePool[]; END. Ê~˜Jš¬ÏcÌœÏk œ žœ6žœžœžœžœžœžœ žœžœžœžœÏn œžœžœžœžœ žœžœžœžœžœžœžœ Ðck œžœžœžœ žœžœžœžœžœ(žœžœžœ(žœ žœ žœžœžœžœžœžœ'žœžœžœžœžœžœžœžœžœ*žœŸœžœžœ žœžœžœžœžœ žœžœžœžœžœ žœ  œžœžœžœ"žœžœžœ!žœžœžœžœ/žœžœŸ œžœžœžœžœžœžœžœžœ žœžœ  œgžœŸ œžœžœžœžœžœ žœžœžœžœžœ Ÿœžœžœžœžœ8žœžœSžœŸœžœžœ žœžœžœžœ žœžœžœžœžœ žœžœ#žœ žœžœMœ(œ žœ žœžœžœžœžœžœžœžœ žœžœžœžœžœžœžœžœ9žœžœžœžœŸœžœžœžœ*žœžœžœŸ œžœžœžœ žœžœžœžœ'žœžœžœžœžœžœžœ žœžœžœžœžœžœ%žœœžœžœžœžœ _œ žœžœžœžœ7žœžœžœ žœ#žœ.?œfžœžœžœžœžœ(žœŸœžœžœžœžœžœ&žœžœžœžœžœžœžœžœžœžœžœ žœžœ žœžœžœžœžœœžœžœžœžœžœ žœvžœžœ Ÿœžœ žœžœ žœžœžœžœ 4œžœžœžœžœ žœžœžœžœžœžœ3žœžœžœžœ žœNœ žœžœžœžœžœžœžœFžœžœ!žœ˜½'—…—ÀD