MODULE; IMPORT Text, Word; REVEAL Table = TablePublic BRANDED OBJECT size: CARDINAL; idCreator: IdCreator; ids: REF ARRAY OF Id; OVERRIDES init := InitTable; enter := Enter; lookup := Lookup; setCreator := SetCreator; enterCharsWithValue := EnterCharsWithValue; enterTextWithValue := EnterTextWithValue; END; Id = IdPublic BRANDED OBJECT next: Id; text: Text.T; OVERRIDES toText := ToText; END; Value = ValuePublic BRANDED OBJECT sum, sumOfSums := 0; OVERRIDES init := InitValue; reset := ResetValue; addCharToValue := AddCharToValue; END; <*INLINE*> PROCEDURE M3CHash InitValue (v: Value): Value= BEGIN RETURN v; END InitValue; <*INLINE*> PROCEDUREResetValue (v: Value)= BEGIN v.sum := 0; v.sumOfSums := 0; END ResetValue; <*INLINE*> PROCEDUREAddCharToValue (v: Value; ch: CHAR)= BEGIN v.sum := Word.Plus(v.sum, ORD(ch)); v.sumOfSums := Word.Plus(v.sumOfSums, v.sum); END AddCharToValue; <*INLINE*> PROCEDURECreate ( t: Table; text: Text.T; VAR list: Id) : Id= BEGIN WITH new = t.idCreator.new(text) DO new.next := list; new.text := text; list := new; RETURN new; END; END Create; <*INLINE*> PROCEDUREEqual ( t: Text.T; READONLY chars: ARRAY OF CHAR) : BOOLEAN = BEGIN FOR i := 0 TO LAST(chars) DO IF Text.GetChar(t, i) # chars[i] THEN RETURN FALSE END; END; RETURN TRUE; END Equal; <*INLINE*> PROCEDUREFindChars ( READONLY chars: ARRAY OF CHAR; id: Id) : Id= BEGIN WHILE id # NIL DO IF Text.Length(id.text) = NUMBER(chars) AND Equal(id.text, chars) THEN EXIT; ELSE id := id.next; END; END; RETURN id; END FindChars; PROCEDUREEnterCharsWithValue ( t: Table; v: Value; READONLY chars: ARRAY OF CHAR) : Id = BEGIN WITH id = t.ids[v.sumOfSums MOD t.size], found = FindChars(chars, id) DO IF found # NIL THEN RETURN found; ELSE RETURN Create(t, Text.FromChars(chars), id); END; END; END EnterCharsWithValue; <*INLINE*> PROCEDUREFindText (text: Text.T; id: Id): Id= BEGIN WHILE id # NIL DO IF Text.Equal(id.text, text) THEN EXIT; ELSE id := id.next; END; END; RETURN id; END FindText; PROCEDUREEnterTextWithValue (t: Table; v: Value; text: Text.T): Id= BEGIN WITH id = t.ids[v.sumOfSums MOD t.size], found = FindText(text, id) DO IF found # NIL THEN RETURN found; ELSE RETURN Create(t, text, id); END; END; END EnterTextWithValue; <*INLINE*> PROCEDURETextValue (text: Text.T): Value= VAR v := NEW(Value).init(); BEGIN FOR i := 0 TO Text.Length(text) - 1 DO AddCharToValue(v, Text.GetChar(text, i)); END; (* for *) RETURN v; END TextValue; <*INLINE*> PROCEDUREEnter (t: Table; text: Text.T): Id= BEGIN RETURN EnterTextWithValue(t, TextValue(text), text); END Enter; <*INLINE*> PROCEDURELookup (t: Table; text: Text.T; VAR id: Id): BOOLEAN= VAR tempId := FindText(text, t.ids[TextValue(text).sumOfSums MOD t.size]); BEGIN IF tempId # NIL THEN id := tempId; RETURN TRUE ELSE RETURN FALSE END; END Lookup; TYPE DefaultIdCreator = IdCreator OBJECT OVERRIDES new := DefaultNewId END; <*INLINE*> PROCEDUREDefaultNewId (<*UNUSED*> c: IdCreator; <*UNUSED*> t: Text.T): Id= BEGIN RETURN NEW(Id); END DefaultNewId; <*INLINE*> PROCEDURENewDefaultIdCreator (): DefaultIdCreator= BEGIN RETURN NEW(DefaultIdCreator); END NewDefaultIdCreator; VAR gDefaultIdCreator := NewDefaultIdCreator(); PROCEDUREInitTable ( init: Table; size: CARDINAL; idCreator: IdCreator := NIL): Table= BEGIN IF idCreator = NIL THEN idCreator := gDefaultIdCreator END; init.size := size; init.idCreator := idCreator; init.ids := NEW(REF ARRAY OF Id, size); RETURN init; END InitTable; <*INLINE*> PROCEDURESetCreator (t: Table; idCreator: IdCreator): IdCreator= VAR old := t.idCreator; BEGIN t.idCreator := idCreator; RETURN old; END SetCreator; <*INLINE*> PROCEDUREToText (id: Id): TEXT= BEGIN RETURN id.text; END ToText; BEGIN END M3CHash.