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.