Article View: comp.lang.modula2
Article #1069Generic Lists in Modula-2
From: Peter.M..Perchansky Peter M. Per...
Date: Thu, 09 Aug 1990 03:47
Date: Thu, 09 Aug 1990 03:47
416 lines
12271 bytes
12271 bytes
IMPLEMENTATION MODULE PMPDeque;
(*---------- Procedures from JPI's TopSpeed Modula II -------------*)
FROM Lib IMPORT Compare;
FROM SYSTEM IMPORT ADDRESS, BYTE, SIZE;
FROM Storage IMPORT ALLOCATE, Available, DEALLOCATE;
(*-----------------------------------------------------------------*)
(*---------- Procedures from PMP's Library Modules ----------------*)
FROM PMPLow IMPORT _Move;
(*-----------------------------------------------------------------*)
TYPE
Deques = POINTER TO DequeNodes; (* opaque type defined *)
DequeNodes = RECORD (* node *)
contents : ADDRESS; (* contents of node *)
size : CARDINAL; (* size of contents *)
next : Deques; (* pointer to next node *)
previous : Deques; (* pointer to prev node *)
END;
(*-----------------------------------------------------------------*)
(* Global Variables used internally by PMPDeque. *)
(*-----------------------------------------------------------------*)
VAR
CallError : ErrorHandler; (* client-module installed error proc *)
lastError : DequesStatus; (* set by procedures when error occurs *)
(*-----------------------------------------------------------------*)
(* Utility procedures used internally by PMPDeque. *)
(*-----------------------------------------------------------------*)
PROCEDURE DeleteNode (VAR node: Deques);
VAR
nodeToDelete : Deques; (* save pointer for deletion *)
BEGIN
IF node^.next = node THEN (* Delete last node in deque *)
DEALLOCATE (node^.contents, node^.size);
DEALLOCATE (node, SIZE (DequeNodes));
node := NIL;
ELSE
nodeToDelete := node; (* Delete specified node *)
node := node^.next;
nodeToDelete^.previous^.next := node;
node^.previous := nodeToDelete^.previous;
DEALLOCATE (nodeToDelete^.contents, nodeToDelete^.size);
DEALLOCATE (nodeToDelete, SIZE (DequeNodes));
END;
END DeleteNode;
PROCEDURE InsertNodeAtEnd (node: Deques; VAR deque: Deques);
BEGIN
IF Empty (deque) THEN (* create front *)
node^.next := node;
node^.previous := node;
deque := node;
ELSE (* add to end *)
node^.next := deque;
node^.previous := deque^.previous;
deque^.previous^.next := node;
deque^.previous := node;
END;
END InsertNodeAtEnd;
PROCEDURE SetError (status: DequesStatus);
BEGIN
lastError := status;
CallError (status);
END SetError;
PROCEDURE IgnoreError (status: DequesStatus);
BEGIN
END IgnoreError;
(*-----------------------------------------------------------------*)
(* Procedures exported by PMPDeque. *)
(*-----------------------------------------------------------------*)
PROCEDURE CreateDeque (VAR deque: Deques);
BEGIN
deque := NIL;
END CreateDeque;
PROCEDURE Empty (deque: Deques) : BOOLEAN;
BEGIN
RETURN deque = NIL;
END Empty;
PROCEDURE DestroyDeque (VAR deque: Deques);
BEGIN
WHILE NOT Empty (deque) DO
DeleteNode (deque);
END;
END DestroyDeque;
PROCEDURE Full (size: CARDINAL): BOOLEAN;
BEGIN
RETURN (NOT (Available (SIZE (DequeNodes) + size)));
END Full;
PROCEDURE DequeLength (deque : Deques) : CARDINAL;
VAR
current : Deques; (* cursor used to walk the deque *)
count : CARDINAL; (* node counter *)
BEGIN
count := 0;
IF NOT Empty (deque) THEN
current := deque^.previous; (* start from back of deque *)
REPEAT
INC (count);
current := current^.next; (* and walk forward until *)
UNTIL current = deque^.previous; (* we've reached the back *)
END;
RETURN count;
END DequeLength;
PROCEDURE DequePos (data: ARRAY OF BYTE; deque: Deques): CARDINAL;
VAR
count, (* node counter *)
pos : CARDINAL; (* returned from AsmLib.Compare *)
current : Deques; (* cursor used to walk the deque *)
BEGIN
IF NOT Empty (deque) THEN
count := 0;
current := deque^.previous; (* start from the back of deque *)
REPEAT
INC (count);
current := current^.next;
pos := Compare (ADR (data), current^.contents, current^.size);
UNTIL (current = deque^.previous) OR (pos = current^.size);
IF pos = current^.size THEN (* pos = size upon exact match *)
RETURN count
ELSE
RETURN 0
END;
ELSE
RETURN 0
END;
END DequePos;
PROCEDURE InDeque (data: ARRAY OF BYTE; deque: Deques): BOOLEAN;
BEGIN
RETURN (DequePos (data, deque) # 0);
END InDeque;
PROCEDURE LastError (): DequesStatus;
BEGIN
RETURN lastError;
END LastError;
PROCEDURE InstallErrorHandler (handler: ErrorHandler);
BEGIN
CallError := handler;
END InstallErrorHandler;
PROCEDURE Enqueue (data: ARRAY OF BYTE; VAR deque: Deques);
VAR
newNode : Deques; (* used to create new node *)
dataSize : CARDINAL; (* size of data *)
BEGIN
dataSize := HIGH (data) + 1;
IF NOT Full (dataSize) THEN
ALLOCATE (newNode, SIZE (DequeNodes));
ALLOCATE (newNode^.contents, dataSize);
_Move (ADR (data), newNode^.contents, dataSize);
newNode^.size := dataSize;
InsertNodeAtEnd (newNode, deque);
ELSE
SetError (full);
END;
END Enqueue;
PROCEDURE Push (data: ARRAY OF BYTE; VAR deque: Deques);
BEGIN
Enqueue (data, deque);
END Push;
PROCEDURE Dequeue (VAR data: ARRAY OF BYTE; VAR deque: Deques);
VAR
dataSize : CARDINAL; (* size of data *)
BEGIN
IF NOT Empty (deque) THEN
dataSize := HIGH (data) + 1;
IF deque^.size = dataSize THEN
_Move (deque^.contents, ADR (data), deque^.size);
DeleteNode (deque);
ELSE
SetError (mismatchedSize)
END;
ELSE
SetError (empty);
END;
END Dequeue;
PROCEDURE Pop (VAR data: ARRAY OF BYTE; VAR deque: Deques);
VAR
dataSize : CARDINAL; (* size of data *)
BEGIN
IF NOT Empty (deque) THEN
dataSize := HIGH (data) + 1;
IF deque^.next = deque THEN (* only one node *)
IF deque^.size = dataSize THEN
_Move (deque^.contents, ADR (data), deque^.size);
DeleteNode (deque);
ELSE
SetError (mismatchedSize)
END;
ELSIF deque^.previous^.size = dataSize THEN
_Move (deque^.previous^.contents, ADR (data), deque^.previous^.size);
DeleteNode (deque^.previous);
ELSE
SetError (mismatchedSize)
END;
ELSE
SetError (empty)
END;
END Pop;
PROCEDURE Update (data: ARRAY OF BYTE; nthItem: CARDINAL; VAR deque: Deques);
VAR
current : Deques; (* used to walk the deque *)
dataSize, (* size of data *)
numberOfNodes, (* length of deque *)
count : CARDINAL; (* node counter *)
BEGIN
IF NOT Empty (deque) THEN
numberOfNodes := DequeLength (deque);
IF (nthItem <= numberOfNodes) AND (nthItem > 0) THEN
count := 0;
current := deque^.previous; (* start from back of deque *)
REPEAT
INC (count); (* walk from back until we *)
current := current^.next; (* have the nth Item *)
UNTIL count = nthItem;
dataSize := HIGH (data) + 1;
IF current^.size = dataSize THEN
_Move (ADR (data), current^.contents, current^.size)
ELSE
SetError (mismatchedSize)
END;
ELSE
SetError (noSuchNode)
END;
ELSE
SetError (empty)
END;
END Update;
PROCEDURE Serve (VAR data: ARRAY OF BYTE; nthItem: CARDINAL; VAR deque: Deques);
VAR
current : Deques; (* used to walk the deque *)
dataSize, (* size of data *)
numberOfNodes, (* length of deque *)
count : CARDINAL; (* node counter *)
BEGIN
IF NOT Empty (deque) THEN
numberOfNodes := DequeLength (deque);
IF (nthItem <= numberOfNodes) AND (nthItem > 0) THEN
count := 0;
current := deque^.previous; (* start from back of deque *)
REPEAT
INC (count); (* walk from back until we *)
current := current^.next; (* have the nth Item *)
UNTIL count = nthItem;
dataSize := HIGH (data) + 1;
IF current^.size = dataSize THEN
_Move (current^.contents, ADR (data), current^.size);
IF count = 1 THEN
DeleteNode (deque)
ELSE
DeleteNode (current)
END;
ELSE
SetError (mismatchedSize)
END;
ELSE
SetError (noSuchNode)
END;
ELSE
SetError (empty)
END;
END Serve;
PROCEDURE Front (VAR data: ARRAY OF BYTE; deque: Deques);
VAR
dataSize : CARDINAL; (* size of data *)
BEGIN
IF NOT Empty (deque) THEN
dataSize := HIGH (data) + 1;
IF deque^.size = dataSize THEN
_Move (deque^.contents, ADR (data), deque^.size)
ELSE
SetError (mismatchedSize)
END;
ELSE
SetError (empty)
END;
END Front;
PROCEDURE Back (VAR data: ARRAY OF BYTE; deque: Deques);
VAR
dataSize : CARDINAL; (* size of data *)
BEGIN
IF NOT Empty (deque) THEN
dataSize := HIGH (data) + 1;
IF deque^.previous^.size = dataSize THEN
_Move (deque^.previous^.contents, ADR (data), deque^.previous^.size)
ELSE
SetError (mismatchedSize)
END;
ELSE
SetError (empty)
END;
END Back;
PROCEDURE Top (VAR data: ARRAY OF BYTE; deque: Deques);
BEGIN
Back (data, deque);
END Top;
PROCEDURE Retrieve (VAR data: ARRAY OF BYTE; nthItem: CARDINAL; deque: Deques);
VAR
current : Deques; (* used to walk the deque *)
dataSize, (* size of data *)
numberOfNodes, (* length of deque *)
count : CARDINAL; (* node counter *)
BEGIN
IF NOT Empty (deque) THEN
numberOfNodes := DequeLength (deque);
IF (nthItem <= numberOfNodes) AND (nthItem > 0) THEN
count := 0;
current := deque^.previous; (* start from back of deque *)
REPEAT
INC (count); (* walk from back until we *)
current := current^.next; (* have the nth Item *)
UNTIL count = nthItem;
dataSize := HIGH (data) + 1;
IF current^.size = dataSize THEN
_Move (current^.contents, ADR (data), current^.size)
ELSE
SetError (mismatchedSize)
END;
ELSE
SetError (noSuchNode)
END;
ELSE
SetError (empty)
END;
END Retrieve;
BEGIN (* initialization *)
InstallErrorHandler (IgnoreError);
lastError := none;
END PMPDeque.
--
uucp: uunet!m2xenix!puddle!273!101!Peter.M..Perchansky
Internet: Peter.M..Perchansky@f101.n273.z1.fidonet.org
Technical Details
Message-ID:
<463.26C27680@puddle.fidonet.org>Path:
arc1-ca.pugleaf.net!utzoo!utgpu!news-server.csri.toronto.edu!cs.utexas.edu!uunet!zephyr.ens.tek.com!tektronix!nosun!qiclab!m2xenix!puddle!f101.n273.z1.fidonet.org!Peter.M..PerchanskyShow Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!utzoo!utgpu!news-server.csri.toronto.edu!cs.utexas.edu!uunet!zephyr.ens.tek.com!tektronix!nosun!qiclab!m2xenix!puddle!f101.n273.z1.fidonet.org!Peter.M..Perchansky From: Peter.M..Perchansky@f101.n273.z1.fidonet.org (Peter M. Perchansky) Newsgroups: comp.lang.modula2 Subject: Generic Lists in Modula-2 Message-ID: <463.26C27680@puddle.fidonet.org> Date: 9 Aug 90 03:47:53 GMT Sender: ufgate@puddle.fidonet.org (newsout1.26) Organization: FidoNet node 1:273/101 - Schizophrenia, Fleetwood PA Lines: 416