language-Modula2-0.1: examples/Modula-2_Libraries/C.-Lins_Modula-2_Software_Component_Library/Vol2/QUEUES/QSCUI.MOD
IMPLEMENTATION MODULE QSCUI;
(*==============================================================
Version : 1.00 19 May 1989 C. Lins
Compiler : TopSpeed Modula-2 Compiler
Component: Monolithic Structures - Queue (Opaque version)
Non-priority Non-balking Sequential Circular Unmanaged Iterator
REVISION HISTORY
v1.00 19 May 1989 C. Lins:
Implemented based on QueueSCMI module.
(C) Copyright 1989 Charles A. Lins
==============================================================*)
FROM JPIStorage IMPORT
(*--Proc*) Allocate, Deallocate;
FROM ErrorHandling IMPORT
(*--Type*) HandlerProc,
(*--Proc*) Raise, NullHandler, ExitOnError;
FROM Items IMPORT
(*--Cons*) NullItem,
(*--Type*) Item, AccessProc, LoopAccessProc;
FROM QEnum IMPORT
(*--Type*) Operations, Exceptions, ComponentID;
FROM TypeManager IMPORT
(*--Cons*) NullType,
(*--Type*) TypeID;
(*--------------------*)
TYPE ItemsArray = ARRAY QueueSize OF Item;
TYPE CircularQueue = RECORD
dataID : TypeID; (*-- defined data type *)
size : QueueSize; (*-- maximum # of items *)
length : CARDINAL; (*-- current # of items *)
front : CARDINAL; (*-- current head of the queue *)
items : ItemsArray; (*-- array [1..size] of item *)
END (*-- CircularQueue *);
TYPE Queue = POINTER TO CircularQueue;
(*--------------------*)
VAR queueError : Exceptions;
VAR handlers : ARRAY Exceptions OF HandlerProc;
PROCEDURE QueueError () : Exceptions (*-- out *);
BEGIN
RETURN queueError;
END QueueError;
(*-------------------------*)
PROCEDURE SetHandler ( theError : Exceptions (*-- in *);
theHandler : HandlerProc (*-- in *));
BEGIN
handlers[theError] := theHandler;
END SetHandler;
(*-------------------------*)
PROCEDURE GetHandler ( theError : Exceptions (*-- in *))
: HandlerProc (*-- out *);
BEGIN
RETURN handlers[theError];
END GetHandler;
(*-------------------------*)
PROCEDURE RaiseErrIn ( theRoutine : Operations (*-- in *);
theError : Exceptions (*-- in *));
BEGIN
queueError := theError;
Raise(ComponentID + ModuleID, theRoutine, theError, handlers[theError]);
END RaiseErrIn;
(*-------------------------*)
PROCEDURE Create ( theType : TypeID (*-- in *);
theSize : QueueSize (*-- in *))
: Queue (*-- out *);
CONST staticSize = SIZE(CircularQueue) - SIZE(ItemsArray);
CONST itemSize = SIZE(Item);
VAR newQueue : Queue;
BEGIN
queueError := noerr;
Allocate(newQueue, staticSize + itemSize * theSize);
IF (newQueue = NIL) THEN
RaiseErrIn(create, overflow);
ELSE
WITH newQueue^ DO
dataID := theType;
size := theSize;
length := 0;
front := MIN(QueueSize);
END(*--with*);
END(*--if*);
RETURN newQueue;
END Create;
(*-------------------------*)
PROCEDURE Destroy (VAR theQueue : Queue (*-- inout *));
CONST staticSize = SIZE(CircularQueue) - SIZE(ItemsArray);
CONST itemSize = SIZE(Item);
BEGIN
Clear(theQueue);
IF (queueError = noerr) THEN
Deallocate(theQueue, staticSize + itemSize * theQueue^.size);
END (*--if*);
END Destroy;
(*-------------------------*)
PROCEDURE Clear ( theQueue : Queue (*-- inout *));
BEGIN
queueError := noerr;
IF (theQueue # NIL) THEN
WITH theQueue^ DO
length := 0;
front := MIN(QueueSize);
END (*--with*);
ELSE
RaiseErrIn(clear, undefined);
END (*--if*);
END Clear;
(*-------------------------*)
PROCEDURE Assign ( theQueue : Queue (*-- in *);
VAR toQueue : Queue (*-- inout *));
VAR index : CARDINAL; (*-- loop index over items *)
fromIndex : CARDINAL; (*-- index into source queue *)
toIndex : CARDINAL; (*-- index into target queue *)
BEGIN
queueError := noerr;
IF (theQueue = NIL) THEN
RaiseErrIn(assign, undefined);
ELSIF (theQueue # toQueue) THEN
IF (toQueue = NIL) THEN
WITH theQueue^ DO
toQueue := Create(dataID, size);
END (*--with*);
ELSIF (theQueue^.length <= theQueue^.size) THEN
Clear(toQueue);
toQueue^.dataID := theQueue^.dataID;
ELSE
RaiseErrIn(assign, overflow);
END (*--if*);
IF (queueError = noerr) THEN
WITH theQueue^ DO
fromIndex := front;
toIndex := toQueue^.front;
FOR index := MIN(QueueSize) TO length DO
toQueue^.items[toIndex] := items[fromIndex];
fromIndex := (fromIndex+1) MOD size;
toIndex := (toIndex+1) MOD toQueue^.size;
END (*--for*);
toQueue^.length := length;
END (*--with*);
END (*--if*);
END (*--if*);
END Assign;
(*-------------------------*)
PROCEDURE Arrive ( theQueue : Queue (*-- inout *);
theItem : Item (*-- in *));
BEGIN
queueError := noerr;
IF (theQueue = NIL) THEN
RaiseErrIn(arrive, undefined);
ELSE
WITH theQueue^ DO
IF (length < size) THEN
items[(front+length) MOD size] := theItem;
INC(length);
ELSE
RaiseErrIn(arrive, overflow);
END (*--if*);
END (*--with*);
END (*--if*);
END Arrive;
(*-------------------------*)
PROCEDURE Depart ( theQueue : Queue (*-- inout *));
VAR index : CARDINAL; (*-- loop index over items *)
BEGIN
queueError := noerr;
IF (theQueue = NIL) THEN
RaiseErrIn(depart, undefined);
ELSE
WITH theQueue^ DO
IF (length = 0) THEN
RaiseErrIn(depart, underflow);
ELSE
front := (front+1) MOD size;
DEC(length);
END (*--if*);
END (*--with*);
END (*--if*);
END Depart;
(*-------------------------*)
PROCEDURE IsDefined ( theQueue : Queue (*-- in *))
: BOOLEAN (*-- out *);
BEGIN
RETURN theQueue # NIL;
END IsDefined;
(*-------------------------*)
PROCEDURE IsEmpty ( theQueue : Queue (*-- in *))
: BOOLEAN (*-- out *);
BEGIN
queueError := noerr;
IF (theQueue # NIL) THEN
RETURN (theQueue^.length = 0);
END (*--if*);
RaiseErrIn(isempty, undefined);
RETURN TRUE;
END IsEmpty;
(*-------------------------*)
PROCEDURE IsEqual ( left : Queue (*-- in *);
right : Queue (*-- in *))
: BOOLEAN (*-- out *);
VAR leftIndex : CARDINAL; (*-- loop index left queue items *)
rightIndex: CARDINAL; (*-- loop index right queue items *)
leftBack : CARDINAL; (*-- where left queue ends *)
rightBack : CARDINAL; (*-- where right queue ends *)
BEGIN
queueError := noerr;
IF (left = NIL) OR (right = NIL) THEN
RaiseErrIn(isequal, undefined);
ELSIF (left^.dataID # right^.dataID) THEN
RaiseErrIn(isequal, typeerror);
ELSIF (left^.length = right^.length) THEN
WITH left^ DO
leftIndex := front;
leftBack := (front + length) MOD size;
END (*--with*);
WITH right^ DO
rightIndex := front;
rightBack := (front + length) MOD size;
END (*--with*);
WITH left^ DO
WHILE (leftIndex # leftBack) & (rightIndex # rightBack) DO
IF (items[leftIndex] # right^.items[rightIndex]) THEN
RETURN FALSE;
END (*--if*);
leftIndex := (leftIndex + 1) MOD size;
rightIndex := (rightIndex + 1) MOD right^.size;
END (*--while*);
RETURN (leftIndex = leftBack) & (rightIndex = rightBack);
END (*--with*);
END (*--if*);
RETURN FALSE;
END IsEqual;
(*-------------------------*)
PROCEDURE LengthOf ( theQueue : Queue (*-- in *))
: CARDINAL (*-- out *);
BEGIN
queueError := noerr;
IF (theQueue # NIL) THEN
RETURN theQueue^.length;
END (*--if*);
RaiseErrIn(lengthof, undefined);
RETURN 0;
END LengthOf;
(*-------------------------*)
PROCEDURE SizeOf ( theQueue : Queue (*-- in *))
: CARDINAL (*-- out *);
BEGIN
queueError := noerr;
IF (theQueue # NIL) THEN
RETURN theQueue^.size;
END (*--if*);
RaiseErrIn(sizeof, undefined);
RETURN 0;
END SizeOf;
(*-------------------------*)
PROCEDURE TypeOf ( theQueue : Queue (*-- in *))
: TypeID (*-- out *);
BEGIN
queueError := noerr;
IF (theQueue # NIL) THEN
RETURN theQueue^.dataID;
END (*--if*);
RaiseErrIn(typeof, undefined);
RETURN NullType;
END TypeOf;
(*-------------------------*)
PROCEDURE FrontOf ( theQueue : Queue (*-- in *))
: Item (*-- out *);
BEGIN
queueError := noerr;
IF (theQueue = NIL) THEN
RaiseErrIn(frontof, undefined);
ELSIF (theQueue^.length = 0) THEN
RaiseErrIn(frontof, underflow);
ELSE
RETURN theQueue^.items[theQueue^.front];
END (*--if*);
RETURN NullItem;
END FrontOf;
(*-------------------------*)
PROCEDURE LoopOver ( theQueue : Queue (*-- in *);
theProcess: LoopAccessProc (*-- in *));
VAR index : CARDINAL; (*-- loop index over items *)
back : CARDINAL; (*-- where the queue ends *)
BEGIN
queueError := noerr;
IF (theQueue = NIL) THEN
RaiseErrIn(loopover, undefined);
ELSE
WITH theQueue^ DO
index:= front;
back := (front+length) MOD size;
WHILE (index # back) DO
IF ~theProcess(items[index]) THEN
RETURN;
END (*--if*);
index := (index+1) MOD size;
END (*--while*);
END (*--with*);
END (*--if*);
END LoopOver;
(*-------------------------*)
PROCEDURE Traverse ( theQueue : Queue (*-- in *);
theProcess: AccessProc (*-- in *));
VAR index : CARDINAL; (*-- loop index over items *)
back : CARDINAL; (*-- where the queue ends *)
BEGIN
queueError := noerr;
IF (theQueue = NIL) THEN
RaiseErrIn(traverse, undefined);
ELSE
WITH theQueue^ DO
index:= front;
back := (front+length) MOD size;
WHILE (index # back) DO
theProcess(items[index]);
index := (index+1) MOD size;
END (*--while*);
END (*--with*);
END (*--if*);
END Traverse;
(*-------------------------*)
BEGIN
FOR queueError := MIN(Exceptions) TO MAX(Exceptions) DO
SetHandler(queueError, ExitOnError);
END (*--for*);
SetHandler(noerr, NullHandler);
queueError := noerr;
END QSCUI.