-- SymTabImpl - implementation of symbol table abstraction
-- last change: Russ Atkinson - 16-Sep-81 21:01:24
-- last change: Nori Suzuki - 11-Oct-81 20:35:31
-- filed on: [Indigo]<Sakura>Parser>SymTabImpl.mesa
DIRECTORY
Inline USING [LowHalf],
Rope USING [Compare, Ref],
RopeInline USING [InlineFetch, InlineSize, Lower],
SymTab;
SymTabImpl: MONITOR LOCKS x USING x: Ref
IMPORTS Inline, Rope, RopeInline
EXPORTS SymTab
= BEGIN
Int: TYPE = LONG INTEGER;
Ref: TYPE = REF SymTabRep;
SymTabRep: PUBLIC TYPE =
MONITORED RECORD [mod,size: CARDINAL, case: BOOLEAN, data: REF Array];
NodeRep: TYPE = RECORD [key: Key, val: Val, next: Node];
Node: TYPE = REF NodeRep;
String: TYPE = Rope.Ref;
Key: TYPE = SymTab.Key;
Val: TYPE = SymTab.Val;
EachPairAction: TYPE = SymTab.EachPairAction;
Array: TYPE = RECORD[nodes: SEQUENCE max: CARDINAL OF Node];
-- Private Operations
Hash: PROCEDURE [s: String, mod: CARDINAL] RETURNS [CARDINAL] = BEGIN
size: LONG INTEGER ← RopeInline.InlineSize[s];
IF size = 0 THEN RETURN [0];
{c0: CARDINAL = RopeInline.Lower[RopeInline.InlineFetch[s, 0]] - 0C;
c1: CARDINAL = RopeInline.Lower[RopeInline.InlineFetch[s, size-1]] - 0C;
RETURN [(Inline.LowHalf[size] + c0 + c1) MOD mod]};
END;
-- public operations
Create: PUBLIC PROCEDURE [mod: CARDINAL ← 17, case: BOOLEAN ← TRUE]
RETURNS [Ref]
= BEGIN
index: CARDINAL ← 0;
data: REF Array ← NIL;
IF mod < 1 THEN mod ← 1;
IF mod > 4095 THEN mod ← 4095;
data ← NEW[Array[mod]];
RETURN[NEW[SymTabRep ← [mod: mod, size: 0, case: case, data: data]]];
END;
GetSize: PUBLIC PROCEDURE [x: Ref] RETURNS [CARDINAL] =
{RETURN [x↑.size]};
Fetch: PUBLIC ENTRY PROCEDURE [x: Ref, key: Key]
RETURNS [found: BOOLEAN, storedKey: Key, val: Val] = BEGIN
hash: CARDINAL ← Hash[key, x.mod];
node: Node ← x.data[hash];
case: BOOLEAN ← x.case;
WHILE node # NIL DO
nkey: Key ← node.key;
IF Rope.Compare[key, node.key, case] = 0
THEN RETURN [TRUE, node.key, node.val];
node ← node.next;
ENDLOOP;
RETURN [FALSE, NIL, NIL];
END;
Store: PUBLIC ENTRY PROCEDURE [x: Ref, key: Key, val: Val]
RETURNS [BOOLEAN]
= BEGIN
hash: CARDINAL ← Hash[key, x.mod];
node: Node ← x.data[hash];
head: Node ← node;
case: BOOLEAN ← x.case;
WHILE node # NIL DO
nkey: Key ← node.key;
IF Rope.Compare[key, node.key, case] = 0
THEN {node.val ← val; RETURN [FALSE]};
node ← node.next;
ENDLOOP;
x.data[hash] ← NEW[NodeRep ← [key: key, val: val, next: head]];
x.size ← x.size + 1;
RETURN [TRUE];
END;
Insert: PUBLIC ENTRY PROCEDURE [x: Ref, key: Key, val: Val]
RETURNS [BOOLEAN]
= BEGIN
hash: CARDINAL ← Hash[key, x.mod];
node: Node ← x.data[hash];
head: Node ← node;
case: BOOLEAN ← x.case;
WHILE node # NIL DO
nkey: Key ← node.key;
IF Rope.Compare[key, node.key, case] = 0
THEN RETURN [FALSE];
node ← node.next;
ENDLOOP;
x.data[hash] ← NEW[NodeRep ← [key: key, val: val, next: head]];
x.size ← x.size + 1;
RETURN [TRUE];
END;
Delete: PUBLIC ENTRY PROCEDURE [x: Ref, key: Key] RETURNS [BOOLEAN]
= BEGIN
hash: CARDINAL ← Hash[key, x.mod];
node: Node ← x.data[hash];
head: Node ← node;
case: BOOLEAN ← x.case;
lag: Node ← NIL;
WHILE node # NIL DO
nkey: Key ← node.key;
IF Rope.Compare[key, node.key, case] = 0
THEN {IF lag = NIL THEN x.data[hash] ← node.next
ELSE lag.next ← node.next;
x.size ← x.size - 1;
RETURN [TRUE]};
lag ← node;
node ← node.next;
ENDLOOP;
RETURN [FALSE];
END;
Pairs: PUBLIC PROCEDURE [x: Ref, action: EachPairAction]
RETURNS [quit: BOOLEAN] = BEGIN
node: Node ← NIL;
index: CARDINAL ← 0;
DO
[node, index] ← GetNext[x, node, index];
IF node = NIL THEN RETURN [FALSE];
IF action[node.key, node.val] THEN RETURN [TRUE];
ENDLOOP;
END;
GetNext: ENTRY PROCEDURE [x: Ref, node: Node, index: CARDINAL]
RETURNS [Node, CARDINAL] = {
mod: CARDINAL ← x.mod;
IF node # NIL THEN {
node ← node.next;
IF node # NIL THEN RETURN [node, index];
index ← index + 1}
ELSE index ← 0;
WHILE index < mod DO
node ← x.data[index];
IF node = NIL THEN {index ← index + 1; LOOP};
RETURN [node, index];
ENDLOOP;
RETURN [NIL, mod];
};
END.
Change log:
Fetch returns stored Key as well as Value