🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: comp.lang.modula2
Article #1069

Generic Lists in Modula-2

#1069
From: Peter.M..Perchansky Peter M. Per...
Date: Thu, 09 Aug 1990 03:47
416 lines
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..Perchansky

Show 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