DIRECTORY Checksum, Card4Tab, Card4TabPrivate; Card4TabImpl: CEDAR MONITOR LOCKS x USING x: Ref IMPORTS Checksum EXPORTS Card4Tab = { OPEN Card4Tab, Card4TabPrivate; Impl: TYPE ~ REF Card4TabImplRep; Card4TabImplRep: PUBLIC TYPE = Card4TabPrivate.Card4TabImplRep; minMod: SeqIndex = 2; Create: PUBLIC PROC [mod: SeqIndex, equal: EqualProc, hash: HashProc] RETURNS [Ref] = { seqLen: SeqIndex ~ MAX[mod, minMod]; impl: Impl ~ NEW [Card4TabImplRep ¬ [ hash: hash, equal: equal, size: 0, sizeLimit: seqLen, inhibitCount: 0, data: NEW [Seq[seqLen]] ]]; RETURN [NEW [Card4TabRep ¬ [impl: impl]]]; }; GetSize: PUBLIC ENTRY PROC [x: Ref] RETURNS [INT] = { impl: Impl ~ x.impl; RETURN [impl.size]; }; Hash: PROC [impl: Impl, key: Key] RETURNS [CARDINAL] ~ TRUSTED INLINE { IF impl.hash#NIL THEN RETURN impl.hash[key]; RETURN [Checksum.ComputeChecksum[0, BITS[Key]/BITS[CARD16], LONG[@key]]]}; Equal: PROC [impl: Impl, key: Key, node: Node] RETURNS [BOOL] ~ INLINE {RETURN [key=node.key OR (impl.equal#NIL AND impl.equal[key, node.key])]}; Fetch: PUBLIC ENTRY PROC [x: Ref, key: Key] RETURNS [found: BOOL, val: Val] = { impl: Impl ~ x.impl; index: SeqIndex ¬ Hash[impl, key] MOD impl.data.max; node: Node ¬ impl.data[index]; WHILE node # NIL DO IF Equal[impl, key, node] THEN RETURN [TRUE, node.val]; node ¬ node.next; ENDLOOP; RETURN [FALSE, NIL]; }; Replace: PUBLIC ENTRY PROC [x: Ref, key: Key, val: Val] RETURNS [BOOL] = { impl: Impl ~ x.impl; node: Node ¬ impl.data[Hash[impl, key] MOD impl.data.max]; WHILE node # NIL DO IF Equal[impl, key, node] THEN { node.val ¬ val; RETURN [TRUE]; }; node ¬ node.next; ENDLOOP; RETURN [FALSE]; }; Store: PUBLIC ENTRY PROC [x: Ref, key: Key, val: Val] RETURNS [BOOL] = { impl: Impl ~ x.impl; index: SeqIndex ~ Hash[impl, key] MOD impl.data.max; node: Node ¬ impl.data[index]; WHILE node # NIL DO IF Equal[impl, key, node] THEN {node.val ¬ val; RETURN [FALSE]}; node ¬ node.next; ENDLOOP; impl.data[index] ¬ NEW[NodeRep ¬ [key: key, val: val, next: impl.data[index]]]; IF (impl.size ¬ impl.size + 1) > impl.sizeLimit AND impl.inhibitCount = 0 THEN ReHash[impl]; RETURN [TRUE]; }; Insert: PUBLIC ENTRY PROC [x: Ref, key: Key, val: Val] RETURNS [BOOL] = { impl: Impl ~ x.impl; index: SeqIndex ~ Hash[impl, key] MOD impl.data.max; node: Node ¬ impl.data[index]; WHILE node # NIL DO IF Equal[impl, key, node] THEN RETURN [FALSE]; node ¬ node.next; ENDLOOP; impl.data[index] ¬ NEW[NodeRep ¬ [key: key, val: val, next: impl.data[index]]]; IF (impl.size ¬ impl.size + 1) > impl.sizeLimit AND impl.inhibitCount = 0 THEN ReHash[impl]; RETURN [TRUE]; }; Delete: PUBLIC ENTRY PROC [x: Ref, key: Key] RETURNS [BOOL] = { impl: Impl ~ x.impl; index: SeqIndex ~ Hash[impl, key] MOD impl.data.max; node: Node ¬ impl.data[index]; lag: Node ¬ NIL; WHILE node # NIL DO IF Equal[impl, key, node] THEN { IF lag = NIL THEN impl.data[index] ¬ node.next ELSE lag.next ¬ node.next; impl.size ¬ impl.size - 1; RETURN [TRUE]; }; lag ¬ node; node ¬ node.next; ENDLOOP; RETURN [FALSE]; }; Erase: PUBLIC ENTRY PROC [x: Ref] = { impl: Impl ~ x.impl; FOR i: SeqIndex IN [0..impl.data.max) DO impl.data[i] ¬ NIL ENDLOOP; impl.size ¬ 0; }; Pairs: PUBLIC PROC [x: Ref, action: EachPairAction] RETURNS [quit: BOOL] = { Inhibit: ENTRY PROC [x: Ref] ~ { impl: Impl ~ x.impl; impl.inhibitCount ¬ impl.inhibitCount + 1; }; Release: ENTRY PROC [x: Ref] ~ { impl: Impl ~ x.impl; impl.inhibitCount ¬ impl.inhibitCount - 1; IF impl.inhibitCount#0 THEN RETURN; WHILE impl.size > impl.sizeLimit DO ReHash[impl] ENDLOOP; }; Enumerate: PROC [x: Ref, action: EachPairAction] RETURNS [quit: BOOL ¬ FALSE] ~ { node: Node ¬ NIL; index: CARDINAL ¬ 0; DO [node, index] ¬ GetNext[x, node, index]; IF node = NIL THEN EXIT; IF action[node.key, node.val] THEN RETURN [TRUE]; ENDLOOP; }; Inhibit[x]; quit ¬ Enumerate[x, action ! UNWIND => Release[x]]; Release[x]; }; GetNext: ENTRY PROC [x: Ref, node: Node, index: CARDINAL] RETURNS [Node, CARDINAL] = { impl: Impl ~ x.impl; IF node = NIL THEN index ¬ impl.data.max ELSE { node ¬ node.next; IF node # NIL THEN RETURN [node, index]; }; WHILE index > 0 DO index ¬ index - 1; node ¬ impl.data[index]; IF node # NIL THEN RETURN [node, index]; ENDLOOP; RETURN [NIL, 0]; }; Update: PUBLIC ENTRY PROC [x: Ref, key: Key, action: UpdateAction] = { ENABLE UNWIND => NULL; IF action # NIL THEN { impl: Impl ~ x.impl; index: SeqIndex ¬ Hash[impl, key] MOD impl.data.max; head: Node ¬ impl.data[index]; node: Node ¬ head; lag: Node ¬ NIL; op: UpdateOperation ¬ none; val: Val ¬ NIL; WHILE node # NIL DO next: Node ¬ node.next; IF Equal[impl, key, node] THEN { [op, val] ¬ action[TRUE, node.val]; SELECT op FROM delete => { IF lag = NIL THEN impl.data[index] ¬ next ELSE lag.next ¬ next; impl.size ¬ impl.size - 1; }; store => node.val ¬ val; none => NULL; ENDCASE => ERROR; RETURN; }; lag ¬ node; node ¬ next; ENDLOOP; [op, val] ¬ action[FALSE, NIL]; SELECT op FROM store => { impl.data[index] ¬ NEW[NodeRep ¬ [key: key, val: val, next: head]]; IF (impl.size ¬ impl.size + 1) > impl.sizeLimit AND impl.inhibitCount = 0 THEN ReHash[impl]; }; none, delete => NULL; ENDCASE => ERROR; }; }; Copy: PUBLIC ENTRY PROC [x: Ref] RETURNS [Ref] = { impl: Impl = x.impl; oldData: REF Seq = impl.data; max: CARDINAL = oldData.max; newImpl: Impl = NEW[Card4TabImplRep ¬ impl­]; newData: REF Seq = NEW[Seq[max]]; -- note, all buckets initially NIL newImpl.data ¬ newData; FOR i: NAT IN [0..max) DO oldChain: Node ¬ oldData[i]; IF oldChain # NIL THEN { newTail: Node ¬ NIL; WHILE oldChain # NIL DO new: Node ¬ NEW[NodeRep ¬ [key: oldChain.key, val: oldChain.val, next: NIL]]; IF newTail = NIL THEN newData[i] ¬ new ELSE newTail.next ¬ new; newTail ¬ new; oldChain ¬ oldChain.next; ENDLOOP; }; ENDLOOP; RETURN [NEW[Card4TabRep ¬ [impl: newImpl]]]; }; ReHash: INTERNAL PROC [impl: Impl] = { oldData: REF Seq = impl.data; newData: REF Seq; seek: CARDINAL = impl.data.max * 2; newPTI, newMod: CARDINAL ¬ 0; IF primeTable[PrimeTableSize-1] > LAST[SeqIndex] THEN ERROR; FOR newPTI ¬ 0, newPTI+1 WHILE newPTI+1 < PrimeTableSize AND primeTable[newPTI] < seek DO ENDLOOP; newMod ¬ primeTable[newPTI]; IF newMod = impl.data.max THEN {impl.sizeLimit ¬ LAST[INT]; RETURN}; impl.sizeLimit ¬ newMod; impl.data ¬ newData ¬ NEW [Seq[newMod]]; FOR i: SeqIndex IN [0 .. oldData.max) DO next: Node ¬ NIL; FOR cur: Node ¬ oldData[i], next WHILE cur # NIL DO index: SeqIndex ~ Hash[impl, cur.key] MOD newMod; next ¬ cur.next; cur.next ¬ newData[index]; newData[index] ¬ cur; ENDLOOP; IF next # NIL THEN ERROR; ENDLOOP; }; PrimeTableSize: NAT = 15; primeTable: ARRAY [0 .. PrimeTableSize) OF CARDINAL = [ 00002, 00005, 00011, 00023, 00053, 00113, 00251, 00509, 01019, 02039, 04079, 08179, 16369, 32749, 65519]; }. Θ Card4TabImpl.mesa Copyright Σ 1987, 1988, 1990, 1992 by Xerox Corporation. All rights reserved. For Portable Cedar Russ Atkinson (RRA) July 10, 1990 8:56 am PDT Doug Wyatt, January 22, 1987 11:04:21 am PST Carl Hauser, January 14, 1988 2:41:46 pm PST Last tweaked by Mike Spreitzer on October 17, 1990 4:40 pm PDT Public operations UpdateOperation: TYPE = {none, store, delete}; UpdateAction: TYPE = PROC [found: BOOL, val: Val] RETURNS [op: UpdateOperation _ none, new: Val _ NIL]; ... atomically performs an update action; looks up key and calls action, which returns the desired operation. If op=none, the table is not changed; if op=store, the new value is stored; if op=delete, key is removed from the table. ... atomically copies the table. Carl Hauser, January 14, 1988 2:40:13 pm PST changes for Portable Cedar changes to: Hash made a no-op for 32 bit machines. It was an XOR of the two halves of the word. Allows for potentially larger tables. Κ ₯•NewlineDelimiter –(cedarcode) style™headšœ™Icodešœ ΟeœC™NLšΠbl™L™-L™,L™,L™>—˜šΟk ˜ Lšœ$˜$——šΟn œŸœŸ˜LšŸœŸœ˜LšŸœ ˜LšŸœ ˜LšœŸœ˜#L˜LšœŸœŸœ˜!LšœŸœŸœ#˜?—šœ™L˜L˜š œŸœŸœ3Ÿœ ˜XLšœŸœ˜$šœ Ÿœ˜%Lšœ˜Lšœ,˜,LšœŸœ˜Lšœ˜—LšŸœŸœ˜*Lšœ˜—L˜š  œŸœŸœŸœ ŸœŸœ˜5L˜LšŸœ ˜Lšœ˜L˜—š  œŸœŸœŸœŸœŸœ˜GLšŸœ ŸœŸœŸœ˜,Lš ŸœŸœŸœŸœŸœ ˜JL˜—š œŸœ$ŸœŸœ˜=Lš œŸœŸœŸœ ŸœŸœ˜SL˜—š  œŸœŸœŸœŸœ Ÿœ˜OL˜Lšœ"Ÿœ˜4L˜šŸœŸœŸ˜LšŸœŸœŸœŸœ ˜7L˜LšŸœ˜—LšŸœŸœŸœ˜Lšœ˜L˜—š  œŸœŸœŸœŸœŸœ˜JL˜Lšœ'Ÿœ˜:šŸœŸœŸ˜šŸœŸœ˜ L˜LšŸœŸœ˜Lšœ˜—L˜LšŸœ˜—LšŸœŸœ˜Lšœ˜L˜—š  œŸœŸœŸœŸœŸœ˜HL˜Lšœ"Ÿœ˜4L˜šŸœŸœŸ˜šŸœ˜LšŸœŸœŸœ˜&—L˜LšŸœ˜—LšœŸœ9˜OšŸœ.ŸœŸ˜NLšœ ˜ —LšŸœŸœ˜Lšœ˜L˜—š  œŸœŸœŸœŸœŸœ˜IL˜Lšœ"Ÿœ˜4L˜šŸœŸœŸ˜LšŸœŸœŸœŸœ˜.L˜LšŸœ˜—LšœŸœ9˜OLšŸœ.ŸœŸœ˜\LšŸœŸœ˜Lšœ˜L˜—š  œŸœŸœŸœŸœŸœ˜?L˜Lšœ"Ÿœ˜4L˜Lšœ Ÿœ˜šŸœŸœŸ˜šŸœŸœ˜ LšŸœŸœŸœŸœ˜IL˜LšŸœŸœ˜Lšœ˜—L˜ L˜LšŸœ˜—LšŸœŸœ˜Lšœ˜L˜—š œŸœŸœŸœ ˜%L˜Lš Ÿœ ŸœŸœŸœŸœ˜DL˜Lšœ˜L˜—š  œŸœŸœ"ŸœŸœ˜Lš œŸœŸœ ˜ L˜L˜*L˜—š œŸœŸœ ˜ L˜L˜*LšŸœŸœŸœ˜#LšŸœŸœŸœ˜9L˜—š   œŸœ"ŸœŸœŸœ˜QLšœ Ÿœ˜LšœŸœ˜šŸ˜L˜(LšŸœŸœŸœŸœ˜LšŸœŸœŸœŸœ˜1LšŸœ˜—L˜—L˜ LšœŸœ˜3L˜ Lšœ˜L˜—š  œŸœŸœŸœŸœŸœ˜VL˜LšŸœŸœŸœ˜(šŸœ˜L˜LšŸœŸœŸœŸœ˜(L˜—šŸœ Ÿ˜L˜L˜LšŸœŸœŸœŸœ˜(LšŸœ˜—LšŸœŸœ˜L˜L˜—L˜šœŸœ™.L™—šœŸ™šœŸœ Ÿœ ™LšŸœ)Ÿœ™5—L™—š œŸœŸœŸœ-˜FLšœη™ηLšŸœŸœŸœ˜šŸœ ŸœŸœ˜L˜Lšœ"Ÿœ˜4L˜L˜Lšœ Ÿœ˜L˜Lšœ Ÿœ˜šŸœŸœŸ˜L˜šŸœŸœ˜ LšœŸœ ˜#šŸœŸ˜šœ ˜ LšŸœŸœŸœŸœ˜?L˜L˜—L˜LšœŸœ˜ LšŸœŸœ˜—LšŸœ˜L˜—L˜ L˜ LšŸœ˜—LšœŸœŸœ˜šŸœŸ˜šœ ˜ LšœŸœ-˜CšŸœ.ŸœŸ˜NLšœ ˜ —Lšœ˜—LšœŸœ˜LšŸœŸœ˜—L˜—L˜—L˜š  œŸœŸœŸœ Ÿœ ˜2Lšœ ™ L˜Lšœ Ÿœ˜LšœŸœ˜LšœŸœ˜-Lšœ ŸœŸœ Οc"˜EL˜šŸœŸœŸœ Ÿ˜L˜šŸœ ŸœŸœ˜LšœŸœ˜šŸœ ŸœŸ˜Lšœ Ÿœ8Ÿœ˜MLšŸœ ŸœŸœŸœ˜?L˜L˜LšŸœ˜—L˜—LšŸœ˜—LšŸœŸœ!˜,L˜L™—š œŸœŸœ˜&Lšœ Ÿœ˜Lšœ Ÿœ˜LšœŸœ˜#LšœŸœ˜LšŸœ Ÿœ ŸœŸœ˜