UXStringsImpl.mesa
Copyright Ó 1988, 1989, 1991 by Xerox Corporation. All rights reserved.
Created by Christian Jacobi, March 31, 1988 12:19:45 pm PST
Christian Jacobi, March 31, 1988 5:40:20 pm PST
Carl Hauser, February 16, 1989 3:09:31 pm PST
Chauser, April 26, 1990 4:26 pm PDT
Willie-s, August 8, 1991 5:41 pm PDT
DIRECTORY
RefText,
Rope,
UXStrings;
UXStringsImpl: CEDAR MONITOR
IMPORTS RefText, Rope
EXPORTS UXStrings
~ BEGIN OPEN UXStrings;
ToRope: PUBLIC PROC [from: CString, maxLength: INT ¬ LAST[INT]] RETURNS [r: Rope.ROPE] = TRUSTED {
len, pos: INT ¬ 0;
PerChar: PROC RETURNS [c: CHAR] = TRUSTED {
c ¬ from­[pos]; pos ¬ pos+1;
};
IF from=NIL THEN RETURN[NIL];
WHILE from­[len]#'\000 AND len < maxLength DO len ¬ len + 1 ENDLOOP;
IF len = 0 THEN RETURN[NIL];
RETURN [Rope.FromProc[len, PerChar]];
};
CharSequence: TYPE ~ RECORD[
seq: PACKED SEQUENCE COMPUTED CARD OF CHAR
];
Create: PUBLIC PROC [from: REF] RETURNS [string: CString] = {
WITH from SELECT FROM
r: Rope.ROPE => {
len: INT ¬ Rope.Length[r];
rtn: REF CharSequence ¬ NEW[CharSequence[len+1]];
TRUSTED {
FOR i: INT IN [0..len) DO rtn[i] ¬ r.Fetch[i] ENDLOOP;
rtn[len] ¬ '\000;
};
string ¬ LOOPHOLE[rtn];
};
r: REF TEXT => {
len: INT ¬ RefText.Length[r];
rtn: REF CharSequence ¬ NEW[CharSequence[len+1]];
TRUSTED {
FOR i: INT IN [0..len) DO rtn[i] ¬ r[i] ENDLOOP;
rtn[len] ¬ '\000;
};
string ¬ LOOPHOLE[rtn];
};
ENDCASE =>
IF from=NIL
THEN TRUSTED {
rtn: REF CharSequence ¬ NEW[CharSequence[1]];
rtn[0] ¬ '\000;
string ¬ LOOPHOLE[rtn];
}
ELSE ERROR; --not implemented type
};
CreateSpace: PUBLIC PROC [size: INT] RETURNS [string: CString] ~ {
rtn: REF CharSequence ¬ NEW[CharSequence[size+1]];
string ¬ LOOPHOLE[rtn];
};
CopyRefToString: PUBLIC UNSAFE PROC [ref: REF, string: CString] ~ UNCHECKED {
rtn: REF CharSequence ¬ LOOPHOLE[string];
WITH ref SELECT FROM
r: Rope.ROPE => {
len: INT ¬ Rope.Length[r];
TRUSTED {
FOR i: INT IN [0..len) DO rtn[i] ¬ r.Fetch[i] ENDLOOP;
rtn[len] ¬ '\000;
};
};
r: REF TEXT => {
len: INT ¬ RefText.Length[r];
TRUSTED {
FOR i: INT IN [0..len) DO rtn[i] ¬ r[i] ENDLOOP;
rtn[len] ¬ '\000;
};
};
ENDCASE =>
IF ref=NIL
THEN TRUSTED {
rtn[0] ¬ '\000;
}
ELSE ERROR; --not implemented type
};
ViewRefText: PUBLIC UNSAFE PROC [from: REF TEXT] RETURNS [string: CString] ~ {
RETURN[ LOOPHOLE[LOOPHOLE[from, CARD]+UNITS[TEXT[0]]]]
};
Monitored global variables:
StringIndex: TYPE = [0..1];
StringMaxLength: ARRAY StringIndex OF INT = [100, 512];
NStringsToAllocate: ARRAY StringIndex OF NAT = [8, 2];
available: ARRAY StringIndex OF LIST OF CString ¬ ALL[NIL];
reserved: ARRAY StringIndex OF LIST OF CString ¬ 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: ErrorCode] = CODE;
CreateScratch: PUBLIC PROC [from: REF] RETURNS [string: CString] ~ {
WITH from SELECT FROM
r: Rope.ROPE => {
len: INT ¬ Rope.Length[r];
rtn: POINTER TO CharSequence ¬ LOOPHOLE[ObtainScratch[len]];
TRUSTED {
FOR i: INT IN [0..len) DO rtn[i] ¬ r.Fetch[i] ENDLOOP;
rtn[len] ¬ '\000;
};
string ¬ LOOPHOLE[rtn];
};
r: REF TEXT => {
len: INT ¬ RefText.Length[r];
rtn: POINTER TO CharSequence ¬ LOOPHOLE[ObtainScratch[len]];
TRUSTED {
FOR i: INT IN [0..len) DO rtn[i] ¬ r[i] ENDLOOP;
rtn[len] ¬ '\000;
};
string ¬ LOOPHOLE[rtn];
};
ENDCASE =>
IF from=NIL
THEN TRUSTED {
rtn: POINTER TO CharSequence ¬ LOOPHOLE[ObtainScratch[0]];
rtn[0] ¬ '\000;
string ¬ LOOPHOLE[rtn];
}
ELSE ERROR; --not implemented type
};
ObtainScratch: PUBLIC ENTRY PROC [nChars: INT] RETURNS [CString] = TRUSTED {
i: StringIndex ¬ 0;
avail: LIST OF CString;
Bump[obtainCalled];
FOR i IN [0 .. LAST[StringIndex]] DO
IF nChars <= StringMaxLength[i] THEN EXIT;
REPEAT FINISHED => {
too large for pool
Bump[nCharsTooLarge];
RETURN [CreateSpace[nChars]];
};
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 CString;
Bump[availEmpty];
r ¬ reserved[i];
UNTIL r.rest.rest = NIL DO r ¬ r.rest ENDLOOP;
avail ¬ r.rest; r.rest ¬ NIL; avail.first ¬ CreateSpace[StringMaxLength[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[0] # '\000 THEN RETURN WITH ERROR Error[clientModifiedReleasedString];
RETURN [avail.first];
};
ReleaseScratch: PUBLIC ENTRY PROC [s: CString] = TRUSTED {
i: StringIndex ¬ 0;
r, l: LIST OF CString;
IF s = NIL THEN RETURN;
FOR i IN [0 .. LAST[StringIndex]] DO
r ¬ reserved[i];
WHILE (l ¬ r.rest) # NIL DO
IF l.first = s THEN {
r.rest ¬ l.rest;
l.rest ¬ available[i].rest; available[i].rest ¬ l;
s[0] ¬ '\000;
RETURN;
};
r ¬ l;
ENDLOOP;
ENDLOOP;
};
InitializeScratchPool: ENTRY PROC [] = {
FOR i: StringIndex IN StringIndex DO
reserved[i] ¬ CONS[NIL, NIL];
construct a list of NStringsToAllocate[i]+1 nodes.
FOR j: NAT IN [0..NStringsToAllocate[i]] DO
available[i] ¬ CONS[NIL, available[i]];
ENDLOOP;
ENDLOOP;
FOR i: StringIndex IN StringIndex DO
allocate a string of length StringMaxLength[i] for each node but the first.
l: LIST OF CString ¬ available[i].rest;
WHILE l # NIL DO
l.first ¬ CreateSpace[StringMaxLength[i]];
l ¬ l.rest;
ENDLOOP;
ENDLOOP;
};
InitializeScratchPool[];
END.
CHauser February 16, 1989: reworked interface and impl to make returned values from Create and CreateSpace legitimate object pointers, eliminating the need for clients to hold onto another value to keep the string pointers valid.
CHauser April 26, 1990: added scratch pool.