File: MxMap.m3 Last Modified On Tue Mar 15 15:33:19 PST 1994 By kalsow
MODULE; REVEAL T = BRANDED "MxMap.T" REF RECORD n_used : INTEGER := 0; data : Contents; END; PROCEDURE MxMap New (initialSize: CARDINAL): T = VAR t := NEW (T); BEGIN t.data := NEW (Contents, MAX (16, initialSize)); RETURN t; END New; PROCEDUREGet (t: T; k: Key): Value = VAR x0 := k MOD NUMBER (t.data^); VAR x := x0; BEGIN LOOP WITH z = t.data[x] DO IF (z.key = k) THEN RETURN z.value END; IF (z.value = NIL) THEN RETURN NIL END; END; INC (x); IF (x > LAST (t.data^)) THEN x := 0 END; IF (x = x0) THEN RETURN NIL END; END; END Get; PROCEDUREGetDirect (t: T; index: INTEGER): Value = BEGIN IF (0 <= index) AND (index <= LAST (t.data^)) THEN RETURN t.data[index].value; ELSE RETURN NIL; END; END GetDirect; PROCEDUREGetIndex (t: T; k: Key): INTEGER = VAR x0 := k MOD NUMBER (t.data^); VAR x := x0; BEGIN LOOP WITH z = t.data [x] DO IF (z.key = k) THEN RETURN x END; IF (z.value = NIL) THEN RETURN MISSING END; END; INC (x); IF (x > LAST (t.data^)) THEN x := 0 END; IF (x = x0) THEN RETURN MISSING END; END; END GetIndex; PROCEDUREInsert (t: T; k: Key; v: Value) = VAR x0 := k MOD NUMBER (t.data^); VAR x := x0; BEGIN LOOP WITH z = t.data [x] DO IF (z.key = k) THEN (* a new value for an existing key *) z.value := v; RETURN; ELSIF (z.value = NIL) THEN (* an empty hole => insert it here *) z.key := k; z.value := v; INC (t.n_used); IF (2 * t.n_used > NUMBER (t.data^)) THEN Expand (t) END; RETURN; END; END; INC (x); IF (x > LAST (t.data^)) THEN x := 0 END; IF (x = x0) THEN (* no free slots *) Expand (t) END; END; END Insert; PROCEDUREExpand (t: T) = VAR old := t.data; VAR n := NUMBER (old^); BEGIN t.n_used := 0; t.data := NEW (Contents, 2 * n); FOR i := 0 TO n-1 DO WITH z = old[i] DO IF (z.value # NIL) THEN Insert (t, z.key, z.value) END; END; END; END Expand; PROCEDUREDelete (t: T; k: Key) = VAR x0 := k MOD NUMBER (t.data^); VAR x := x0; v: Value; BEGIN LOOP WITH z = t.data [x] DO IF (z.key = k) THEN (* a new value for an existing key *) (* this is the value to delete *) z.value := NIL; DEC (t.n_used); EXIT; ELSIF (z.value = NIL) THEN (* an empty hole => nobody to delete *) RETURN; END; END; INC (x); IF (x > LAST (t.data^)) THEN x := 0 END; IF (x = x0) THEN (* no match *) RETURN; END; END; (* reinsert the elements that may be rehashes of the target *) LOOP INC (x); IF (x > LAST (t.data^)) THEN x := 0; END; WITH z = t.data[x] DO v := z.value; IF (v = NIL) THEN (* the end of the rehash chain *) RETURN; END; z.value := NIL; DEC (t.n_used); Insert (t, z.key, v); END; END; END Delete; PROCEDUREGetData (t: T): Contents = BEGIN IF (t = NIL) THEN RETURN NIL ELSE RETURN t.data; END; END GetData; BEGIN END MxMap.