AtomImpl.Mesa. Implements basic atom and property list operations. Resides in boot file. Rest of procedures in Atom interface are exported by AtomImpl.
Last Modified On January 17, 1983 1:38 pm by Warren Teitelman
Last Modified On September 19, 1983 8:48 pm by Paul Rovner
Last Edited by: Levin, September 20, 1983 3:34 pm
DIRECTORY
Atom USING [PropList, DottedPairNode],
AtomPrivate USING [AtomRec],
PrincOpsUtils USING [BITSHIFT],
Rope USING [ROPE, Text, FromChar, InlineFlatten, NewText, FromRefText],
SafeStorageOps USING [AcquireBasicLiterals],
SafeStorage USING [GetPermanentZone]
;
AtomImpl: CEDAR MONITOR -- protects the ATOM dictionary and all PropLists
IMPORTS PrincOpsUtils, Rope, SafeStorageOps, SafeStorage
EXPORTS Atom, AtomPrivate
SHARES Rope
= BEGIN
Constants
HashSize: INTEGER = 4093; -- prime;
Types, Errors, Global Variables
PropList: TYPE = Atom.PropList;
String: TYPE = LONG POINTER TO READONLY TEXT;
AtomRec: TYPE = AtomPrivate.AtomRec;
RefAtomRec: TYPE = REF AtomRec;
bridge from opaque ATOM to concrete as defined in AtomPrivate
AtomDictionaryIndex: TYPE = [0..HashSize);
AAtomDict: TYPE = ARRAY AtomDictionaryIndex OF RefAtomRec;
ComparisonOutcome: TYPE = {less, greater, equal};
atomZone: ZONE = SafeStorage.GetPermanentZone[];
atomDictionary: REF AAtomDict ← atomZone.NEW[AAtomDict ← ALL[NIL]];
NILNotAnAtom: PUBLIC ERROR = CODE;
emptyAtom: ATOM;
Creating Atoms
EmptyAtom: PUBLIC PROC RETURNS[ATOM] = {RETURN[emptyAtom]};
MakeAtom: PUBLIC PROC [pName: Rope.ROPE] RETURNS[ATOM] = TRUSTED {
t: Rope.Text = Rope.InlineFlatten[pName];
this, prev: RefAtomRec;
hash: AtomDictionaryIndex;
l: CARDINAL;
IF t = NIL THEN RETURN[EmptyAtom[]];
l ← t.length;
IF l MOD 2 = 1 -- fill residue char with 0
THEN {
w: CARDINAL ← PrincOpsUtils.BITSHIFT[LOOPHOLE[t[l-1], UNSPECIFIED], 8];
p: LONG POINTER TO CARDINAL;
l ← l + 1;
p ← LOOPHOLE[t, LONG POINTER TO CARDINAL] + SIZE[TEXT[0]] + l/2 - 1;
IF p^ # w THEN p^ ← w};
[this, prev, hash] ← LookUpAtom[t];
IF this # NIL THEN RETURN[LOOPHOLE[this]];
here if not found. Make a new ATOM.
this ← atomZone.NEW[AtomRec ← [pName: t]];
InsertAtom[atom: this, prev: prev, hash: hash];
RETURN[LOOPHOLE[this]];
};
exported to AtomPrivate
UnsafeMakeAtom: PUBLIC PROC[pName: String] RETURNS[ATOM] = TRUSTED{
this, prev: RefAtomRec;
hash: AtomDictionaryIndex;
l: CARDINAL;
oddLength: BOOLEANFALSE;
rt: Rope.Text;
IF pName = NIL THEN RETURN[NIL];
l ← pName.length;
IF l MOD 2 = 1 -- fill residue char with 0 (NOTE violation of READONLY!!!)
THEN {
w: CARDINAL = PrincOpsUtils.BITSHIFT[LOOPHOLE[pName[l-1], UNSPECIFIED], 8];
p: LONG POINTER TO CARDINAL;
oddLength ← TRUE;
l ← l + 1;
p ← LOOPHOLE[pName + SIZE[TEXT[0]] + l/2 - 1];
IF p^ # w THEN p^ ← w -- NOTE violation of READONLY!!!
};
[this, prev, hash] ← LookUpAtom[LOOPHOLE[pName, Rope.Text]];
IF this # NIL THEN RETURN[LOOPHOLE[this]];
here if not found. Make a new ATOM.
rt ← Rope.NewText[l];
rt.length ← pName.length;
FOR i: CARDINAL IN [0..pName.length) DO rt[i] ← pName[i] ENDLOOP;
IF oddLength THEN {rt.length ← l; rt[l-1] ← LOOPHOLE[0]; rt.length ← l-1};
this ← atomZone.NEW[AtomRec ← [pName: rt]];
InsertAtom[atom: this, prev: prev, hash: hash];
RETURN[LOOPHOLE[this]]};
MakeAtomFromChar: PUBLIC PROC [char: CHARACTER] RETURNS[ATOM] = TRUSTED {
RETURN[MakeAtom[Rope.FromChar[char]]];
};
MakeAtomFromRefText: PUBLIC PROC [rt: REF READONLY TEXT] RETURNS[ATOM] = TRUSTED {
this, prev: RefAtomRec;
hash: AtomDictionaryIndex;
l: CARDINAL;
IF rt = NIL THEN RETURN[EmptyAtom[]];
l ← rt.length;
IF l MOD 2 = 1 -- fill residue char with 0
THEN {
w: CARDINAL ← PrincOpsUtils.BITSHIFT[LOOPHOLE[rt[l-1], UNSPECIFIED], 8];
p: LONG POINTER TO CARDINAL;
old: CARDINAL;
oldSaved: BOOL ← FALSE;
l ← l + 1;
p ← LOOPHOLE[rt, LONG POINTER TO CARDINAL] + SIZE[TEXT[0]] + l/2 - 1;
IF p^ # w THEN {old ← p^; p^ ← w; oldSaved ← TRUE};
[this, prev, hash] ← LookUpAtom[LOOPHOLE[rt, Rope.Text]];
IF oldSaved THEN p^ ← old;
}
ELSE [this, prev, hash] ← LookUpAtom[LOOPHOLE[rt, Rope.Text]];
IF this # NIL THEN RETURN[LOOPHOLE[this]];
here if not found. Make a new ATOM.
this ← atomZone.NEW[AtomRec ← [pName: Rope.FromRefText[rt]]];
InsertAtom[atom: this, prev: prev, hash: hash];
RETURN[LOOPHOLE[this, ATOM]];
};
ATOMToAtom: PROC [atom: ATOM] RETURNS [RefAtomRec] = TRUSTED INLINE {
RETURN[LOOPHOLE[atom, RefAtomRec]];
};
ATOMToPropList: PROC [atom: ATOM] RETURNS [PropList] = INLINE {
RETURN[NARROW[ATOMToAtom[atom].propList, PropList]];
};
property list operations (for atoms and types)
property lists are alists, rather than list of ref any, so that the property list functions do not have to check the type of each entry to make sure it is a dotted pair. When automatic narrowing arrives, then maybe want to just make property list a list of typed objects.
GetPropertyList: PUBLIC PROC [atom: ATOM] RETURNS[PropList] = {
RETURN[IF atom = NIL THEN NIL ELSE ATOMToPropList[atom]];
treat NIL as an atom for purposes of GetProp
};
PutProp: PUBLIC PROC [atom: ATOM, prop: REF ANY, val: REF ANY] = {
IF atom = NIL THEN ERROR NILNotAnAtom;
ATOMToAtom[atom].propList
← PutPropOnList[propList: ATOMToPropList[atom], prop: prop, val: val];
};
PutPropOnList: PUBLIC ENTRY PROC [propList: PropList, prop: REF ANY, val: REF ANY] RETURNS[PropList] = {
ENABLE UNWIND => NULL;
lst: PropList ← propList;
lst1: PropList ← NIL;
UNTIL lst = NIL DO
IF lst.first.key = prop THEN
BEGIN
lst.first.val ← val;
RETURN[propList];
END;
lst1 ← lst;
lst ← lst.rest;
ENDLOOP;
prop not found on property list
lst ← CONS[NEW[Atom.DottedPairNode ← [key: prop, val: val]], NIL];
IF lst1 = NIL THEN RETURN[lst]
ELSE IF lst1.rest = NIL THEN {lst1.rest ← lst; RETURN[propList]} -- add at end --
ELSE ERROR ; -- shouldnt happen
}; -- of PutPropOnList
GetProp: PUBLIC PROC [atom: ATOM, prop: REF ANY] RETURNS[REF ANY] = {
IF atom = NIL THEN RETURN[NIL] -- treat NIL as an atom for purposes of GetProp
ELSE RETURN[GetPropFromList[propList: ATOMToPropList[atom], prop: prop]];
};
GetPropFromList: PUBLIC ENTRY PROC [propList: PropList, prop: REF ANY] RETURNS[REF ANY] = {
ENABLE UNWIND => NULL;
FOR lst: PropList ← propList, lst.rest UNTIL lst = NIL DO
IF lst.first.key = prop THEN RETURN[lst.first.val];
ENDLOOP;
RETURN[NIL];
};
RemProp: PUBLIC PROC [atom: ATOM, prop: REF ANY] = {
IF atom = NIL THEN RETURN;
ATOMToAtom[atom].propList ← RemPropFromList[ATOMToPropList[atom], prop];
};
RemPropFromList: PUBLIC ENTRY PROC [propList: PropList, prop: REF ANY] RETURNS[PropList] = {
ENABLE UNWIND => NULL;
lst, lst1: PropList ← NIL;
lst ← propList;
UNTIL lst = NIL DO
IF lst.first.key = prop THEN
{IF lst1 = NIL THEN RETURN[lst.rest]
ELSE {lst1.rest ← lst.rest; RETURN[propList]};
};
lst1 ← lst;
lst←lst.rest;
ENDLOOP;
RETURN[propList];
};
GetPName: PUBLIC PROC [atom: ATOM] RETURNS [pName: Rope.Text] = {
IF atom = NIL THEN ERROR NILNotAnAtom;
RETURN[ATOMToAtom[atom].pName];
};
MapAtoms: PUBLIC PROC [proc: PROC[atom: ATOM]] = TRUSTED {
proc1: PROC [atm: ATOM] RETURNS[stop: BOOLEAN] = CHECKED {
proc[atm];
RETURN[FALSE];
}; -- of proc1
[] ← FindAtom[proc: proc1];
};
FindAtom: PUBLIC PROC [proc: PROC[atom: ATOM] RETURNS[stop: BOOL]]
RETURNS[ATOM--NIL if was not stopped--] = {
FOR atom: ATOM ← Next[NIL], Next[atom] UNTIL atom = NIL
DO IF proc[atom] THEN RETURN[atom] ENDLOOP;
RETURN[NIL]};
Next: ENTRY PROC[atom: ATOMNIL] RETURNS[ATOM] =
TRUSTED INLINE{
a: RefAtomRec = LOOPHOLE[atom];
IF a # NIL AND a.link # NIL THEN RETURN[a.link];
FOR adi: CARDINAL ← (IF a = NIL THEN 0 ELSE (Hash[LOOPHOLE[a.pName]] + 1)), adi + 1
UNTIL adi = HashSize
DO IF atomDictionary[adi] # NIL THEN RETURN[LOOPHOLE[atomDictionary[adi]]];
ENDLOOP;
RETURN[NIL]};
returns [NIL, ptr to last atom, hash index] if not found
LookUpAtom: ENTRY PROC[s: Rope.Text]
RETURNS[atom: RefAtomRec, prev: RefAtomRec, hash: AtomDictionaryIndex] =
TRUSTED INLINE {
prev ← NIL;
hash ← Hash[s];
FOR atom ← atomDictionary[hash], LOOPHOLE[atom.link] UNTIL atom = NIL
DO
SELECT CompareStrings[s, atom.pName] FROM
equal => RETURN;
greater => {atom ← NIL; EXIT};
ENDCASE;
prev ← atom;
ENDLOOP};
InsertAtom: ENTRY PROC[atom: RefAtomRec, prev: RefAtomRec, hash: AtomDictionaryIndex] =
TRUSTED INLINE {
IF prev = NIL
THEN {atom.link ← LOOPHOLE[atomDictionary[hash]]; atomDictionary[hash] ← atom}
ELSE {atom.link ← prev.link; prev.link ← LOOPHOLE[atom]}};
CompareStrings: INTERNAL PROC[leftString, rightString: Rope.Text]
RETURNS[ComparisonOutcome] =
TRUSTED INLINE {
lLength: CARDINAL = (leftString.length+1)/2;
rLength: CARDINAL = (rightString.length+1)/2;
lp: LONG POINTER TO CARDINAL = LOOPHOLE[leftString, LONG POINTER TO CARDINAL] + SIZE[TEXT[0]];
rp: LONG POINTER TO CARDINAL = LOOPHOLE[rightString, LONG POINTER TO CARDINAL] + SIZE[TEXT[0]];
FOR i: CARDINAL IN [0..MIN[lLength, rLength])
DO
lw: CARDINAL = (lp + i)^;
rw: CARDINAL = (rp + i)^;
IF lw < rw THEN RETURN[less] ELSE IF lw > rw THEN RETURN[greater];
ENDLOOP;
RETURN
[IF lLength = rLength THEN equal
ELSE IF lLength < rLength THEN less ELSE greater]};
stolen from TexHash.mesa
Hash: INTERNAL PROC[s: Rope.Text] RETURNS[AtomDictionaryIndex] =
INLINE {
acc: CARDINAL ← 0;
FOR i: CARDINAL IN [0..MIN[7, s.length])
DO acc ← 7*acc+LOOPHOLE[s[i], CARDINAL] ENDLOOP;
RETURN[acc MOD HashSize]};
START HERE
TRUSTED{SafeStorageOps.AcquireBasicLiterals[CODE[AtomRec]]};
emptyAtom ← MakeAtom[""];
END.