atom/src/AtomWeak.m3


Copyright (C) 1994, Digital Equipment Corp.

MODULE AtomWeak EXPORTS Atom;

IMPORT TextF, TextToRefanyTable, WeakRef;

REVEAL T = BRANDED REF TEXT;

VAR
  mutex := NEW(MUTEX);
  table := TextToRefanyTable.New();

PROCEDURE FromText(t: TEXT): T =
  VAR
    r: REFANY;
    a: T;
  BEGIN
    LOCK mutex DO
      IF table.in(t, r) THEN
        a := WeakRef.ToRef(NARROW(r, WeakRef.T))
      ELSE
        a := NEW(T);
        a^ := t;
        EVAL table.put(t, WeakRef.FromRef(a, CleanUpProc))
      END
    END;
    RETURN a
  END FromText;

PROCEDURE CleanUpProc(READONLY w: T; a: REFANY) =
  VAR r: REFANY;
  BEGIN
    LOCK mutex DO
      IF NOT table.delete(NARROW(a, T)^, r) THEN <*ASSERT FALSE*> END
    END
  END CleanUpProc;

PROCEDURE ToText(a: T): TEXT =
  BEGIN
    RETURN a^
  END ToText;

PROCEDURE Hash(a: T): INTEGER =
  (* Stolen from John Ellis's Modula-2+ TextTable.Hash. *)
  CONST Multiplier  = -1664117991;
    (* = LOOPHOLE( Round( .6125423371 * 2^32 ), INTEGER ) *)
  VAR hash: INTEGER := 0;
  BEGIN
    FOR i := 0 TO (* Text.Length(a^)-1 *) MAX (0, NUMBER (a^^) - 1) - 1 DO
      hash := hash * Multiplier + ORD( (* Text.GetChar(a^) *) a^[i] )
    END;
    RETURN hash
  END Hash;

BEGIN
END AtomWeak.