-- JaMHashImpl.mesa
-- Last changed by Doug Wyatt,  1-Oct-81 13:43:53

DIRECTORY
  JaMBasic USING [Object],
  JaMDict USING [],
  JaMVM USING [GetText],
  Inline USING [BITSHIFT, BITXOR, HighHalf, LowHalf];

JaMHashImpl: PROGRAM
IMPORTS JaMVM, Inline
EXPORTS JaMDict = {
OPEN VM:JaMVM, JaMBasic;

HashObject: PUBLIC PROC[key: Object] RETURNS[CARDINAL] = {
  -- hashes object key into a CARDINAL
  -- Expects caller to do: (h MOD range) to allow for different ranges with same key
  WITH k: key SELECT FROM
    integer => RETURN[Inline.LowHalf[k.ivalue]];
    real => RETURN[Inline.HighHalf[k.rvalue]];
    boolean => RETURN[LOOPHOLE[k.bvalue]];
    name => RETURN[k.id.index];
    string => RETURN[HashString[k]];
    stream => RETURN[k.index];
    command => RETURN[k.index];
    ENDCASE => RETURN[0];
  };

-- HashString and HashText must be consistent!

maxLength: CARDINAL = 20;

HashString: PUBLIC PROC[s: string Object] RETURNS[CARDINAL] = {
  text: STRING ← [maxLength]; VM.GetText[s,text];
  RETURN[InlineHash[text,s.length]] };

HashText: PUBLIC PROC[text: LONG STRING] RETURNS[CARDINAL] = {
  RETURN[InlineHash[text,text.length]] };

InlineHash: PROC[text: LONG STRING, h: CARDINAL] RETURNS[CARDINAL] = INLINE {
  len: CARDINAL ← MIN[text.length,maxLength];
  FOR i: CARDINAL IN[1..MIN[3,len]) DO
    h ← Inline.BITXOR[Inline.BITSHIFT[h,1], text[i]];
    ENDLOOP;
  IF len >= 2 THEN FOR i: CARDINAL IN[len - 2..len) DO
    h ← Inline.BITXOR[Inline.BITSHIFT[h,1], text[i]];
    ENDLOOP;
  RETURN[h] };

}.