-- AtomsPrivateImpl.mesa -- Simple hash-table implementation of CedarPrivateAtoms.MakeAtom -- Last Modified On 8-Mar-82 10:30:26 by Paul Rovner DIRECTORY Inline, Rope USING[ROPE, Text], RopeInline USING[NewText, InlineFlatten], RTBasic USING[Type], RTLoader USING[AcquireBasicLiterals], RTTypesBasic USING[GetCanonicalType, Type], RTTypesBasicPrivate USING[NotifyAtomRecType], SafeStorage USING[NewZone], AtomsPrivate; AtomsPrivateImpl: MONITOR -- protects the ATOM dictionary IMPORTS Inline, RopeInline, RTLoader, RTTypesBasic, RTTypesBasicPrivate, SafeStorage EXPORTS AtomsPrivate SHARES Rope = BEGIN OPEN AtomsPrivate; -- CONSTANTS HashSize: INTEGER = 4093; -- prime -- TYPES String: TYPE = LONG POINTER TO READONLY TEXT; Atom: TYPE = REF AtomRec; AtomDictionaryIndex: TYPE = [0..HashSize); AAtomDict: TYPE = ARRAY AtomDictionaryIndex OF Atom; ComparisonOutcome: TYPE = {less, greater, equal}; -- VARIABLES atomDictionary: REF AAtomDict ← NEW[AAtomDict ← ALL[NIL]]; atomZone: ZONE = SafeStorage.NewZone[sr: quantized]; -- PROCEDURES GetAtom: PUBLIC PROC[pName: Rope.ROPE] RETURNS[ATOM] = { t: Rope.Text = RopeInline.InlineFlatten[pName]; this, prev: Atom; hash: AtomDictionaryIndex; l: CARDINAL; IF t = NIL THEN RETURN[NIL]; l ← t.length; IF l MOD 2 = 1 -- fill residue char with 0 THEN { w: CARDINAL = Inline.BITSHIFT[t[l-1], 8]; p: LONG POINTER TO UNSPECIFIED; l ← l + 1; p ← LOOPHOLE[t, LONG POINTER TO UNSPECIFIED] + 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]]}; UnsafeMakeAtom: PUBLIC PROC[pName: String] RETURNS[ATOM] = { this, prev: Atom; hash: AtomDictionaryIndex; l: CARDINAL; oddLength: BOOLEAN ← FALSE; 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 = Inline.BITSHIFT[pName[l-1], 8]; p: LONG POINTER TO UNSPECIFIED; 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 ← RopeInline.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]]}; EnumerateAtoms: PUBLIC PROC[ callee: PROC[ATOM] RETURNS[stop: BOOLEAN] ] RETURNS[ATOM--NIL if was not stopped--] = { FOR atom: ATOM ← Next[NIL], Next[atom] UNTIL atom = NIL DO IF callee[atom] THEN RETURN[atom]; ENDLOOP; RETURN[NIL]}; Next: ENTRY PROC[atom: ATOM ← NIL] RETURNS[ATOM] = INLINE { a: Atom = 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: Atom, prev: Atom, hash: AtomDictionaryIndex] = 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: Atom, prev: Atom, hash: AtomDictionaryIndex] = 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] = 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 atomRecType: RTTypesBasic.Type = RTTypesBasic.GetCanonicalType[CODE[AtomRec]]; RTTypesBasicPrivate.NotifyAtomRecType[atomRecType]; RTLoader.AcquireBasicLiterals[atomRecType]; END.