[Oberon] How to mimic an associative array

Yaroslav Romanchenko tobject at bk.ru
Fri Dec 3 16:20:05 CET 2010


Simple implementation of string hash.

MODULE StringHash;

IMPORT

	Strings, Commands;

CONST

	(* Prime number for hash table *)
	PRIME = 977;

TYPE

	HashTable  = ARRAY PRIME OF
		RECORD
			key, value: Strings.String;
		END;

VAR
	hash: HashTable;
	nCollisions: LONGINT;

	PROCEDURE hashSearch(bAddAllowed: BOOLEAN; CONST key: ARRAY OF CHAR; VAR value: Strings.String): BOOLEAN;
	VAR
		d: INTEGER;
		i, h: LONGINT;
		bFound, bExit: BOOLEAN;
	BEGIN

		bExit := FALSE;
		bFound := FALSE;
		d := 1;

		(* simple hash function *)
		h := 0;
		FOR i := 0 TO Strings.Length(key) - 1 DO
			h := (h + ORD(key[i])) MOD PRIME
		END;

		WHILE ~(bFound OR bExit) DO
			IF hash[h].key = NIL THEN (* new entry *)
				bExit := TRUE;
				IF bAddAllowed THEN
					hash[h].key := Strings.NewString(key);
					hash[h].value := value
				END
			ELSIF hash[h].key^ = key THEN (* match *)
				bFound := TRUE;
				value := hash[h].value
			ELSE (* collision *)

				INC(nCollisions);

				h := h + d; d := d + 2;
				IF h >= PRIME THEN h := h - PRIME END;

				(* Table owerflow! *)
				IF d = PRIME THEN
					bExit := TRUE;
					ASSERT(d # PRIME)
				END

			END
		END;

		RETURN bFound

	END hashSearch;
	
PROCEDURE Test*(context: Commands.Context);
VAR
	b: BOOLEAN;
	s: Strings.String;
BEGIN
	(* Add entries *)
	s := Strings.NewString("Duke");
	b := hashSearch(TRUE, "name", s);
	s := Strings.NewString("63");
	b := hashSearch(TRUE, "age", s);
	
	context.out.Ln;
	(* Try to find entries *)
	IF hashSearch(FALSE, "name", s) THEN
		context.out.String(s^); context.out.Ln
	END;
	IF hashSearch(FALSE, "age", s) THEN
		context.out.String(s^); context.out.Ln
	END;
	
END Test;

PROCEDURE HashStat*(context: Commands.Context);
VAR
	i, n: INTEGER;
BEGIN
	n := 0;
	FOR i := 0 TO PRIME - 1 DO
		IF hash[i].key # NIL THEN
			INC(n)
		END
	END;
	IF n = 0 THEN
		context.out.Ln;
		context.out.String("Hash table not yet initialized.");
		context.out.Ln
	ELSE
		context.out.Ln;
		context.out.Int(n, 1);
		context.out.String(" of ");
		context.out.Int(PRIME, 1);
		context.out.String(" hash table cells used. Ratio: ");
		context.out.Float(n / PRIME, 20);
		context.out.Ln;
		context.out.String("Number of collisions: ");
		context.out.Int(nCollisions, 1);
		context.out.Ln
	END
END HashStat;


PROCEDURE Init;
VAR
	i: INTEGER;
BEGIN
	FOR i := 0 TO PRIME - 1 DO
		hash[i].key := NIL;
		hash[i].value := NIL;
	END
END Init;

BEGIN
	Init
END StringHash.

StringHash.Test ~
StringHash.HashStat ~

SystemTools.Free StringHash~


---
Cheers, SAGE
http://sage.com.ua/




More information about the Oberon mailing list