packages feed

language-Modula2-0.1: examples/Modula-2_Libraries/andrea-m2/lib/generic/largesets.mod

IMPLEMENTATION MODULE LargeSets;

(* V2.1, John Andrea, Jun.22/93 -add Copy and Duplicate *)
(* V2.0, John Andrea, Jun.17/93 -determine bitset size ar runtime *)
(* V1.0, John Andrea, Apr.5/92 *)
(* This code may be freely used and distributed, it may not be sold *)

FROM SYSTEM IMPORT TSIZE, ADDRESS;
FROM Storage IMPORT ALLOCATE, DEALLOCATE;

TYPE
   LargeSet = POINTER TO RECORD
                  start    :ADDRESS;    (* memory address of the first item *)
                  min, max :CARDINAL;   (* size of the set *)
                  sets     :CARDINAL;   (* number of bitsets used *)
                  in_last  :CARDINAL;   (* number of bits in the last set *)
               END;
   DataType  = BITSET;
   DataPoint = POINTER TO DataType;

VAR
  bset_bits, bset_bytes :CARDINAL;
  empty, full           :BITSET;
  i                     :CARDINAL;

(* -------------------------------------------------------- *)
PROCEDURE Offset( a :LargeSet; x :CARDINAL; VAR set, bit :CARDINAL );
(* calculate the memory offset to the item from the first item *)
VAR
  count_bit :CARDINAL;
BEGIN
  count_bit := x - a^.min;
  set       := count_bit DIV bset_bits;
  (* and how far into this set is the dot that we need *)
  bit       := count_bit - set * bset_bits;
END Offset;

(* -------------------------------------------------------- *)
PROCEDURE Build( VAR a :LargeSet; min, max :CARDINAL );
VAR
  i, n :CARDINAL;
BEGIN
  NEW( a );

  IF min > max THEN
   i   := min;
   min := max;
   max := i;
  END;

  a^.min := min;   a^.max := max;

  n := max - min + 1;

  a^.in_last := n MOD bset_bits;

  IF a^.in_last = 0 THEN
    a^.in_last := bset_bits;   (* already a multiple of bset_bits *)
  ELSE
    n := n + bset_bits - a^.in_last;    (* bump up to a multiple of bset_bits *)
  END;

  a^.sets := n DIV bset_bits;

  ALLOCATE( a^.start, a^.sets * bset_bytes );       (* grab bytes from memory *)
  Empty( a );
END Build;

(* -------------------------------------------------------- *)
PROCEDURE Destroy( VAR a :LargeSet );
BEGIN
  DEALLOCATE( a^.start, a^.sets * bset_bytes );
  DISPOSE( a );
END Destroy;

(* -------------------------------------------------------- *)
PROCEDURE Empty( a :LargeSet );
VAR
  adra :DataPoint;
  i, k :CARDINAL;
BEGIN
  k := 0;
  FOR i := 1 TO a^.sets DO
     adra  := a^.start + k;
     adra^ := empty;
     k     := k + bset_bytes;
  END;
END Empty;

(* -------------------------------------------------------- *)
PROCEDURE Fill( a :LargeSet );
VAR
  adra :DataPoint;
  i, k :CARDINAL;
BEGIN
  k := 0;
  FOR i := 1 TO a^.sets DO
     adra  := a^.start + k;
     adra^ := full;
     k     := k + bset_bytes;
  END;
END Fill;

(* -------------------------------------------------------- *)
PROCEDURE Incl( a :LargeSet; x :CARDINAL );
VAR
  adra                 :DataPoint;
  which_set, which_bit :CARDINAL;
BEGIN
  IF ( a^.min <= x ) & ( x <= a^.max ) THEN

    Offset( a, x, which_set, which_bit );
    adra := a^.start + which_set * bset_bytes;
    INCL( adra^, which_bit );

  END;
END Incl;

(* -------------------------------------------------------- *)
PROCEDURE Excl( a :LargeSet; x :CARDINAL );
VAR
  adra                 :DataPoint;
  which_set, which_bit :CARDINAL;
BEGIN
  IF ( a^.min <= x ) & ( x <= a^.max ) THEN

    Offset( a, x, which_set, which_bit );
    adra := a^.start + which_set * bset_bytes;
    EXCL( adra^, which_bit );

  END;
END Excl;

(* -------------------------------------------------------- *)
PROCEDURE In( a :LargeSet; x :CARDINAL ) :BOOLEAN;
VAR
  adra                 :DataPoint;
  which_set, which_bit :CARDINAL;
  result               :BOOLEAN;
BEGIN
  IF ( a^.min <= x ) & ( x <= a^.max ) THEN

    Offset( a, x, which_set, which_bit );
    adra   := a^.start + which_set * bset_bytes;
    result := which_bit IN adra^;

  ELSE
    result := FALSE;
  END;
  RETURN result;
END In;

(* -------------------------------------------------------- *)
PROCEDURE Not( a :LargeSet );
VAR
  adra :DataPoint;
  i, k :CARDINAL;
BEGIN
  k := 0;
  FOR i := 1 TO a^.sets DO
     adra  := a^.start + k;
     adra^ := adra^ / full;    (* Xor with <all bits> *)
     k     := k + bset_bytes;
  END;
END Not;

(* -------------------------------------------------------- *)
PROCEDURE Equal( a, b :LargeSet ) :BOOLEAN;
VAR
  adra, adrb :DataPoint;
  i, k       :CARDINAL;
  ok         :BOOLEAN;
BEGIN

   IF ( a^.min = b^.min ) & ( a^.max = b^.max ) THEN
     ok := TRUE;

     k  := 0;
     i  := 1;
     WHILE ( i <= a^.sets - 1 ) & ok DO
       adra := a^.start + k;
       adrb := b^.start + k;
       ok   := adra^ = adrb^;
       i    := i + 1;
       k    := k + bset_bytes;
     END;

     (* only the used portion of the last set should be compared *)
     IF ok THEN
       adra := a^.start + k;
       adrb := b^.start + k;

       i := 0;
       WHILE ( i < a^.in_last ) & ok DO
         ok := ( i IN adra^ ) = ( i IN adrb^ );
         i  := i + 1;
       END;

     END;

   ELSE
     ok := FALSE;
   END;

   RETURN ok;
END Equal;

(* -------------------------------------------------------- *)
PROCEDURE Copy( a, b :LargeSet );
VAR
  adra, adrb :DataPoint;
  i, k :CARDINAL;
BEGIN
  IF ( a^.min = b^.min ) & ( a^.max = b^.max ) THEN

    k := 0;
    FOR i := 1 TO a^.sets DO
       adra  := a^.start + k;
       adrb  := b^.start + k;
       adrb^ := adra^;
       k     := k + bset_bytes;
    END;

  END;
END Copy;

(* -------------------------------------------------------- *)
PROCEDURE Duplicate( a :LargeSet; VAR b :LargeSet );
BEGIN
   Build( b, a^.min, a^.max );
   Copy( a, b );
END Duplicate;

BEGIN
   bset_bytes := TSIZE( DataType );
   bset_bits  := bset_bytes * 8;

   empty := {};

   full  := {};
   FOR i := 0 TO bset_bits - 1 DO
     INCL( full, i );
   END;

END LargeSets.