m3tools/src/M3SetVal.m3


 Copyright 1996-2000 Critical Mass, Inc. All rights reserved.    
 See file COPYRIGHT-CMASS for details. 

MODULE M3SetVal;

IMPORT Word;

REVEAL T = BRANDED "M3SetVal.T" REF ARRAY OF INTEGER;

PROCEDURE NewEmpty (n_elts: INTEGER): T =
  VAR n_words := (n_elts + BITSIZE (INTEGER) - 1) DIV BITSIZE (INTEGER);
  BEGIN
    IF (n_elts < 0) THEN RETURN NIL; END;
    RETURN NEW (T, n_words);
  END NewEmpty;

PROCEDURE Compare (a, b: T): INTEGER =
  VAR le, eq, ge := TRUE;  ax, bx: INTEGER;
  BEGIN
    IF (a = NIL) OR (b = NIL) THEN RETURN -99; END;
    IF NUMBER (a^) # NUMBER (b^) THEN RETURN -99; END;
    FOR i := 0 TO LAST (a^) DO
      ax := a[i];  bx := b[i];
      IF (ax # bx)             THEN eq := FALSE; END;
      IF Word.Or (ax, bx) # bx THEN le := FALSE; END;
      IF Word.Or (ax, bx) # ax THEN ge := FALSE; END;
    END;
    IF    (le AND NOT eq) THEN RETURN -1
    ELSIF (ge AND NOT eq) THEN RETURN +1
    ELSIF (eq)            THEN RETURN  0
    ELSE                       RETURN -99;
    END;
  END Compare;

PROCEDURE Union (a, b: T): T =
  VAR c: T;
  BEGIN
    IF (a = NIL) OR (b = NIL) THEN RETURN NIL; END;
    IF NUMBER (a^) # NUMBER (b^) THEN RETURN NIL; END;
    c := NEW (T, NUMBER (a^));
    FOR i := 0 TO LAST (a^) DO
      c[i] := Word.Or (a[i], b[i]);
    END;
    RETURN c;
  END Union;

PROCEDURE Intersection (a, b: T): T =
  VAR c: T;
  BEGIN
    IF (a = NIL) OR (b = NIL) THEN RETURN NIL; END;
    IF NUMBER (a^) # NUMBER (b^) THEN RETURN NIL; END;
    c := NEW (T, NUMBER (a^));
    FOR i := 0 TO LAST (a^) DO
      c[i] := Word.And (a[i], b[i]);
    END;
    RETURN c;
  END Intersection;

PROCEDURE Difference (a, b: T): T =
  VAR c: T;
  BEGIN
    IF (a = NIL) OR (b = NIL) THEN RETURN NIL; END;
    IF NUMBER (a^) # NUMBER (b^) THEN RETURN NIL; END;
    c := NEW (T, NUMBER (a^));
    FOR i := 0 TO LAST (a^) DO
      c[i] := Word.And (a[i], Word.Not (b[i]));
    END;
    RETURN c;
  END Difference;

PROCEDURE SymDifference (a, b: T): T =
  VAR c: T;
  BEGIN
    IF (a = NIL) OR (b = NIL) THEN RETURN NIL; END;
    IF NUMBER (a^) # NUMBER (b^) THEN RETURN NIL; END;
    c := NEW (T, NUMBER (a^));
    FOR i := 0 TO LAST (a^) DO
      c[i] := Word.Xor (a[i], b[i]);
    END;
    RETURN c;
  END SymDifference;

PROCEDURE Include (a: T;  elt: INTEGER): T =
  VAR
    c: T;
    elt_word := elt DIV BITSIZE (INTEGER);
    elt_bit  := elt - elt_word * BITSIZE (INTEGER);
  BEGIN
    IF (a = NIL) THEN RETURN NIL; END;
    IF (elt < 0) OR (elt_word >= NUMBER (a^)) THEN RETURN NIL; END;
    c := NEW (T, NUMBER (a^));
    c^ := a^;
    c [elt_word] := Word.Or (c[elt_word], Word.LeftShift (1, elt_bit));
    RETURN c;
  END Include;

PROCEDURE Exclude (a: T;  elt: INTEGER): T =
  VAR
    c: T;
    elt_word := elt DIV BITSIZE (INTEGER);
    elt_bit  := elt - elt_word * BITSIZE (INTEGER);
  BEGIN
    IF (a = NIL) THEN RETURN NIL; END;
    IF (elt < 0) OR (elt_word >= NUMBER (a^)) THEN RETURN NIL; END;
    c := NEW (T, NUMBER (a^));
    c^ := a^;
    c [elt_word] := Word.And (c[elt_word], Word.Not (Word.LeftShift (1, elt_bit)));
    RETURN c;
  END Exclude;

PROCEDURE IsMember (a: T;  elt: INTEGER): BOOLEAN =
  VAR
    elt_word := elt DIV BITSIZE (INTEGER);
    elt_bit  := elt - elt_word * BITSIZE (INTEGER);
  BEGIN
    IF (a = NIL) THEN RETURN FALSE; END;
    IF (elt < 0) OR (elt_word >= NUMBER (a^)) THEN RETURN FALSE; END;
    RETURN Word.And (a[elt_word], Word.LeftShift (1, elt_bit)) # 0;
  END IsMember;

BEGIN
END M3SetVal.