packages feed

language-Modula2-0.1: examples/Modula-2_Libraries/C.-Lins_Modula-2_Software_Component_Library/Vol1/BAGS/BAGCSBMI.MOD

IMPLEMENTATION MODULE BagCSBMI;
(*==============================================================
    Version  : 1.00  30 Apr 1989  C. Lins
    Compiler : TopSpeed Modula-2
    Code Size: R-  bytes
    Component: Monolithic Structure - Bag
               Character Sequential Bounded Managed Iterator

    INTRODUCTION
    This module supports the abstract data type bag for discrete
    values of CHARs.

    REVISION HISTORY
    v1.00  30 Apr 1989  C. Lins
      Initial implementation for TopSpeed Modula-2.

    (C) Copyright 1989 Charles A. Lins
==============================================================*)

FROM JPIStorage IMPORT
    (*--Proc*) Allocate, Deallocate;

FROM CharItems IMPORT
    (*--Type*) Item, Continue;

FROM BagEnum IMPORT
    (*--Type*) Exceptions, Operations, ComponentID;

FROM ErrorHandling IMPORT
    (*--Type*) HandlerProc,
    (*--Proc*) NullHandler, Raise, ExitOnError;

    (*-----------------------*)

TYPE  ItemsArray = ARRAY Item OF CARDINAL;
TYPE  BoundedBag = RECORD
        items : ItemsArray;
      END (*-- BoundedBag *);

TYPE  Bag = POINTER TO BoundedBag;


    (*-----------------------*)

VAR   theEmptyBag : ItemsArray; (*-- Predefined bag, initialized to 0 *)

    (*-----------------------*)
    (*--     EXCEPTIONS    --*)

VAR   bagError   : Exceptions;
VAR   handlers   : ARRAY Exceptions OF HandlerProc;


    (*-----------------------*)

PROCEDURE BagError    ()             : Exceptions (*-- out   *);
BEGIN
  RETURN bagError;
END BagError;
(*----------------------------*)

PROCEDURE GetHandler  (    ofError   : Exceptions  (*-- in    *))
                                     : HandlerProc (*-- out   *);
BEGIN
  RETURN handlers[ofError];
END GetHandler;
(*----------------------------*)

PROCEDURE SetHandler  (    ofError   : Exceptions  (*-- in    *);
                           toHandler : HandlerProc (*-- in    *));
BEGIN
  handlers[ofError] := toHandler;
END SetHandler;
(*----------------------------*)

PROCEDURE RaiseErrIn (    theRoutine : Operations    (*-- in    *);
                          theError   : Exceptions    (*-- in    *));
BEGIN
  bagError := theError;
  Raise(ComponentID + ModuleID, theRoutine, theError, handlers[theError]);
END RaiseErrIn;
(*----------------------------*)

PROCEDURE Recreate   (VAR theBag : Bag     (*-- inout *))
                                 : BOOLEAN (*-- out   *);
BEGIN
  IF (theBag = NullBag) THEN
    theBag := Create();
  END (*--if*);
  RETURN (theBag # NIL);
END Recreate;
(*----------------------------*)


    (*---------------------------------*)
    (*--        CONSTRUCTORS         --*)

PROCEDURE Create        ()           : Bag         (*-- out   *);

VAR   newBag : Bag;

BEGIN
  bagError := noerr;
  Allocate(newBag, SIZE(BoundedBag));
  IF (newBag = NullBag) THEN
	RaiseErrIn(create, overflow);
  ELSE
    newBag^.items := theEmptyBag;
  END (*--if*);
  RETURN newBag;
END Create;
(*----------------------------*)

PROCEDURE Destroy       (VAR theBag    : Bag         (*-- inout *));
BEGIN
  Clear(theBag);
  IF (bagError = noerr) THEN
    Deallocate(theBag, SIZE(BoundedBag));
  END (*--if*);
END Destroy;
(*----------------------------*)

PROCEDURE Clear         (VAR theBag    : Bag         (*-- inout *));
BEGIN
  bagError := noerr;
  IF (theBag # NullBag) THEN
    theBag^.items := theEmptyBag;
  ELSE
    RaiseErrIn(clear, undefined);
  END (*--if*);
END Clear;
(*----------------------------*)

PROCEDURE Assign        (    theBag  : Bag         (*-- in    *);
                         VAR toBag   : Bag         (*-- inout *));
BEGIN 
  bagError := noerr;
  IF (theBag # NullBag) THEN
    IF Recreate(toBag) THEN
      toBag^.items := theBag^.items;
    END (*--if*);
  ELSE
    RaiseErrIn(assign, undefined);
  END (*--if*);
END Assign;
(*----------------------------*)

PROCEDURE Include       (    theItem : Item        (*-- in    *);
       	       	         VAR inBag   : Bag         (*-- inout *));
BEGIN
  bagError := noerr;
  IF (inBag # NullBag) THEN
    WITH inBag^ DO
      IF (items[theItem] < MAX(CARDINAL)) THEN
	INC(items[theItem]);
      ELSE
	RaiseErrIn(include, overflow);
      END (*--if*);
    END (*--with*);
  ELSE
    RaiseErrIn(include, undefined);
  END (*--if*);
END Include;
(*----------------------------*)

PROCEDURE Exclude       (    theItem : Item        (*-- in    *);
       	       	         VAR fromBag : Bag         (*-- inout *));
BEGIN
  bagError := noerr;
  IF (fromBag # NullBag) THEN
    WITH fromBag^ DO
      IF (items[theItem] > MIN(CARDINAL)) THEN
	DEC(items[theItem]);
      ELSE
	RaiseErrIn(exclude, notinbag);
      END (*--if*);
    END (*--with*);
  ELSE
    RaiseErrIn(exclude, undefined);
  END (*--if*);
END Exclude;
(*----------------------------*)

PROCEDURE Union         (    left   : Bag         (*-- in    *);
       	       	             right  : Bag         (*-- in    *);
                         VAR toBag  : Bag         (*-- inout *));

VAR   index : Item; (*-- loop index over items *)

BEGIN
  bagError := noerr;
  IF (left # NullBag) & (right # NullBag) THEN
    IF Recreate(toBag) THEN
      WITH toBag^ DO
        FOR index := MIN(Item) TO MAX(Item) DO
          items[index] := left^.items[index] + right^.items[index];
        END (*--for*);
      END (*--with*);
    END (*--if*);
  ELSE
    RaiseErrIn(union, undefined);
  END (*--if*);
END Union;
(*----------------------------*)

PROCEDURE Intersection  (    left   : Bag         (*-- in    *);
       	       	             right  : Bag         (*-- in    *);
                         VAR toBag  : Bag         (*-- inout *));

VAR   index : Item; (*-- loop index over items *)

BEGIN
  bagError := noerr;
  IF (left # NullBag) & (right # NullBag) THEN
    IF Recreate(toBag) THEN
      WITH toBag^ DO
        FOR index := MIN(Item) TO MAX(Item) DO
          IF (left^.items[index] < right^.items[index]) THEN
            items[index] := left^.items[index];
	  ELSE
            items[index] := right^.items[index];
	  END (*--if*);
        END (*--for*);
      END (*--with*);
    END (*--if*);
  ELSE
    RaiseErrIn(intersection, undefined);
  END (*--if*);
END Intersection;
(*----------------------------*)

PROCEDURE Difference    (    left    : Bag         (*-- in    *);
       	       	             right   : Bag         (*-- in    *);
                         VAR toBag   : Bag         (*-- inout *));

VAR   index : Item; (*-- loop index over items *)

BEGIN
  bagError := noerr;
  IF (left # NullBag) & (right # NullBag) THEN
    IF Recreate(toBag) THEN
      WITH toBag^ DO
        FOR index := MIN(Item) TO MAX(Item) DO
	  IF (right^.items[index] = 0) THEN
	    items[index] := left^.items[index];
	  ELSIF (left^.items[index] > right^.items[index]) THEN
            items[index] := left^.items[index] - right^.items[index];
	  ELSE
	    items[index] := 0;
	  END (*--if*);
        END (*--for*);
      END (*--with*);
    END (*--if*);
  ELSE
    RaiseErrIn(difference, undefined);
  END (*--if*);
END Difference;
(*----------------------------*)

PROCEDURE SymDifference (    left    : Bag         (*-- in    *);
       	       	             right   : Bag         (*-- in    *);
                         VAR toBag   : Bag         (*-- inout *));

VAR   index : Item; (*-- loop index over items *)

BEGIN
  bagError := noerr;
  IF (left # NullBag) & (right # NullBag) THEN
    IF Recreate(toBag) THEN
      WITH toBag^ DO
        FOR index := MIN(Item) TO MAX(Item) DO
	  IF (right^.items[index] = 0) THEN
	    items[index] := left^.items[index];
	  ELSIF (left^.items[index] > right^.items[index]) THEN
            items[index] := left^.items[index] - right^.items[index];
	  ELSE
            items[index] := right^.items[index] - left^.items[index];
	  END (*--if*);
        END (*--for*);
      END (*--with*);
    END (*--if*);
  ELSE
    RaiseErrIn(symdifference, undefined);
  END (*--if*);
END SymDifference;
(*----------------------------*)


    (*---------------------------------*)
    (*--          SELECTORS          --*)

PROCEDURE IsDefined     (    theBag    : Bag         (*-- in    *))
                                       : BOOLEAN     (*-- out   *);
BEGIN
  RETURN theBag # NullBag;
END IsDefined;
(*----------------------------*)

PROCEDURE IsEmpty       (    theBag    : Bag         (*-- in    *))
                                       : BOOLEAN     (*-- out   *);

VAR   index : Item; (*-- loop index over items *)

BEGIN
  bagError := noerr;
  IF (theBag # NullBag) THEN
    WITH theBag^ DO
      FOR index := MIN(Item) TO MAX(Item) DO
        IF (items[index] # 0) THEN
          RETURN FALSE;
        END (*--if*);
      END (*--for*);
    END (*--with*);
  ELSE
    RaiseErrIn(isempty, undefined);
  END (*--if*);
  RETURN TRUE;
END IsEmpty;
(*----------------------------*)

PROCEDURE IsEqual       (    left      : Bag         (*-- in    *);
       	       	       	     right     : Bag         (*-- in    *))
                                       : BOOLEAN     (*-- out   *);

VAR   index : Item;   (*-- loop index over items *)

BEGIN
  bagError := noerr;
  IF (left # NullBag) & (right # NullBag) THEN
    WITH left^ DO
      FOR index := MIN(Item) TO MAX(Item) DO
        IF (items[index] # right^.items[index]) THEN
          RETURN FALSE;
        END (*--if*);
      END (*--for*);
    END (*--with*);
    RETURN TRUE;
  ELSE
    RaiseErrIn(isequal, undefined);
  END (*--if*);
  RETURN FALSE;
END IsEqual;
(*----------------------------*)

PROCEDURE NumMembers    (    theBag  : Bag         (*-- in    *))
                                     : CARDINAL    (*-- out   *);

VAR   index : Item;     (*-- loop index over items *)
      count : CARDINAL; (*-- working sum of items in the bag *)

BEGIN
  bagError := noerr;
  count    := 0;
  IF (theBag # NullBag) THEN
    WITH theBag^ DO
      FOR index := MIN(Item) TO MAX(Item) DO
        INC(count, items[index]);
      END (*--for*);
    END (*--with*);
  ELSE
    RaiseErrIn(nummembers, undefined);
  END (*--if*);
  RETURN count;
END NumMembers;
(*----------------------------*)

PROCEDURE UniqueMembers (    theBag  : Bag         (*-- in    *))
                                     : CARDINAL    (*-- out   *);

VAR   index : Item;     (*-- loop index over items *)
      count : CARDINAL; (*-- working sum of unique items in the bag *)

BEGIN
  bagError := noerr;
  count    := 0;
  IF (theBag # NullBag) THEN
    WITH theBag^ DO
      FOR index := MIN(Item) TO MAX(Item) DO
	IF (items[index] > 0) THEN
          INC(count);
	END (*--if*);
      END (*--for*);
    END (*--with*);
  ELSE
    RaiseErrIn(uniquemembers, undefined);
  END (*--if*);
  RETURN count;
END UniqueMembers;
(*----------------------------*)

PROCEDURE IsAMember     (    theItem : Item        (*-- in    *);
       	       	             theBag  : Bag         (*-- in    *))
                                     : BOOLEAN     (*-- out   *);
BEGIN
  bagError := noerr;
  IF (theBag # NullBag) THEN
    RETURN theBag^.items[theItem] > 0;
  ELSE
    RaiseErrIn(ismember, undefined);
  END (*--if*);
  RETURN FALSE;
END IsAMember;
(*----------------------------*)

PROCEDURE NumberOf      (    theItem : Item        (*-- in    *);
       	       	             theBag  : Bag         (*-- in    *))
                                     : CARDINAL    (*-- out   *);
BEGIN
  bagError := noerr;
  IF (theBag # NullBag) THEN
    RETURN theBag^.items[theItem];
  ELSE
    RaiseErrIn(numberof, undefined);
  END (*--if*);
  RETURN 0;
END NumberOf;
(*----------------------------*)

PROCEDURE IsSubset      (    left    : Bag         (*-- in    *);
                             right   : Bag         (*-- in    *))
                                     : BOOLEAN     (*-- out   *);

VAR   index : Item; (*-- loop index over items *)

BEGIN
  bagError := noerr;
  IF (left # NullBag) & (right # NullBag) THEN
    WITH left^ DO
      FOR index := MIN(Item) TO MAX(Item) DO
        IF (items[index] > right^.items[index]) THEN
          RETURN FALSE;
        END (*--if*);
      END (*--for*);
    END (*--with*);
    RETURN TRUE;
  ELSE
    RaiseErrIn(issubset, undefined);
  END (*--if*);
  RETURN FALSE;
END IsSubset;
(*----------------------------*)

PROCEDURE IsProperSubset (    left   : Bag        (*-- in    *);
       	       	       	      right  : Bag        (*-- in    *))
                                     : BOOLEAN    (*-- out   *);
BEGIN
  RETURN IsSubset(left, right) & ~IsEqual(left, right);
END IsProperSubset;
(*----------------------------*)

PROCEDURE LoopOver      (    theBag  : Bag            (*-- in    *);
       	       	       	     process : LoopAccessProc (*-- in    *));

VAR   index : Item; (*-- loop index over items *)

BEGIN
  bagError := noerr;
  IF (theBag # NullBag) THEN
    WITH theBag^ DO
      FOR index := MIN(Item) TO MAX(Item) DO
        IF (items[index] # 0) THEN
          IF ~process(index, items[index]) THEN
            RETURN; (*-- Premature exit, by command of visiting process *)
          END (*--if*);
        END (*--if*);
      END (*--for*);
    END (*--with*);
  ELSE
    RaiseErrIn(loopover, undefined);
  END (*--if*);
END LoopOver;
(*----------------------------*)

PROCEDURE Traverse      (    theBag  : Bag         (*-- in    *);
       	       	       	     process : AccessProc  (*-- in    *));

VAR   index : Item; (*-- loop index over bitsets *)

BEGIN
  bagError := noerr;
  IF (theBag # NullBag) THEN
    WITH theBag^ DO
      FOR index := MIN(Item) TO MAX(Item) DO
        IF (items[index] # 0) THEN
          process(index, items[index]);
        END (*--if*);
      END (*--for*);
    END (*--with*);
  ELSE
    RaiseErrIn(traverse, undefined);
  END (*--if*);
END Traverse;
(*----------------------------*)


(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
(*~~ MODULE INITIALIZATION  ~~*)

VAR   index : Item; (*-- loop index over items *)

BEGIN
  FOR index := MIN(Item) TO MAX(Item) DO
    theEmptyBag[index] := 0;
  END (*--for*);

  FOR bagError := MIN(Exceptions) TO MAX(Exceptions) DO
    handlers[bagError] := ExitOnError;
  END (*--for*);
  handlers[noerr] := NullHandler;
  bagError := noerr;
END BagCSBMI.