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
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.