home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / modula2 / library / queuem2 / deq2.txt < prev    next >
Text File  |  1989-12-15  |  24KB  |  578 lines

  1. (*====================================================================*)
  2. (*                  Peter M. Perchansky                               *)
  3. (*              412-1 Springside, Drive East                          *)
  4. (*                 Shillington, PA  19607                             *)
  5. (*                                                                    *)
  6. (*                  CompuServe 71301,344                              *)
  7. (*                  FidoNet    1:273/101                              *)
  8. (*                  Interlink                                         *)
  9. (*====================================================================*)
  10.  
  11. The following is my implementation of a generic deque using JPI's
  12. TopSpeed Modula-2 (version 1.17).  A deque is a form of double-ended
  13. queue (or stack depending on your point of view).  The deque abstract
  14. data type allows you to do perform queue and stack operations.
  15.  
  16. The queue operations are based on the following:  The front of the
  17. queue is the root node.  Enqueueing data will place the node at the
  18. rear of the queue.  Dequeueing (serving) data will remove the node
  19. from the front of the queue.
  20.  
  21. The stack operations are based on the following:  The top of the stack
  22. is the end node.  Pushing data will place the node at the rear (top)
  23. of the stack.  Popping data will remove data from the rear (top) of
  24. the stack.
  25.  
  26. This library module is generic.  Any data type (both standard and
  27. user-defined) can be operated on in the deque.  You can even mix and
  28. match data types within the deque; however, you are responsible for
  29. keeping track of what types are in the deque.
  30.  
  31. Future versions of this module will include procedures to compare
  32. deques, append one deque to another deque, search for elements within
  33. the deque, etc.
  34.  
  35. Please feel free to contact me via postal mail, CompuServe, FidoNet,
  36. or Interlink (language or Pascal Conference <they are working on
  37. adding a Modula-2 Conference>) if you have any questions or comments.
  38.  
  39.  
  40. <-------------------------- cut here --------------------------------->
  41.  
  42.  
  43. (*====================================================================
  44.   =  Program Id:     PMPDEQUE                                        =
  45.   =  Programmer:     Peter M. Perchansky                             =
  46.   =  Purpose:        Export procedures for dealing with deques.      =
  47.   =  Date Written:   10-29-89                                        =
  48.   ====================================================================*)
  49.  
  50. DEFINITION MODULE PMPDeque;
  51.  
  52. (*------------- Procedures from JPI's TopSpeed Modula II -------------*)
  53. FROM SYSTEM IMPORT BYTE;
  54. (*--------------------------------------------------------------------*)
  55.  
  56.  
  57. TYPE
  58.     Deques;           (* opaque type defined in implementation module *)
  59.  
  60. (*  A deque is a circular queue allowing for both queue and stack     *)
  61. (*  operations.  This module is generic, allowing for operations on   *)
  62. (*  any data type.                                                    *)
  63.  
  64. (*  The deque must be initialized to NIL by calling Create (deque).   *)
  65. (*  Create (deque) should only be called once.  DestroyDeque should   *)
  66. (*  be called when the deque is no longer needed.                     *)
  67.  
  68. (*  Procedures to initialize/remove the deque:                        *)
  69. (*            CreateDeque  - set deque to NIL                         *)
  70. (*            DestroyDeque - remove deque from memory                 *)
  71.  
  72. (*  Functions providing status information on the deque:              *)
  73. (*            Empty        - is deque NIL                             *)
  74. (*            Full         - is deque full                            *)
  75. (*            DequeLength  - number of nodes in deque                 *)
  76. (*            DequePos     - node number containing data (if found)   *)
  77. (*            InDeque      - is data in deque                         *)
  78.  
  79. (*  Procedures to enter data in the deque:                            *)
  80. (*    <queue> Enqueue      - place data in rear of deque              *)
  81. (*    <stack> Push         - place data in rear of deque              *)
  82.  
  83. (*  Procedures to remove data from the deque:                         *)
  84. (*    <queue> Dequeue      - remove data from the front of the deque  *)
  85. (*    <stack> Pop          - remove data from the rear of the deque   *)
  86. (*            Serve        - remove nth item in the deque             *)
  87.  
  88. (*  Procedures to show data in the deque:                             *)
  89. (*    <queue> Front        - show data from the front of the deque    *)
  90. (*    <queue> Back         - show data from the rear of the deque     *)
  91. (*    <stack> Top          - show data at top of the deque            *)
  92. (*            Retrieve     - show data from nth item in the deque     *)
  93.  
  94.  
  95. PROCEDURE CreateDeque  (VAR deque: Deques);
  96. (* Creates the deque by making it NIL                                 *)
  97. (* This procedure must be called prior to performing operations on    *)
  98. (* the deque.                                                         *)
  99.  
  100. PROCEDURE Empty        (deque: Deques): BOOLEAN;
  101. (* Return TRUE if the deque is NIL                                    *)
  102.  
  103. PROCEDURE DestroyDeque (VAR deque: Deques);
  104. (* Destroys the deque by deallocating deque nodes and contents        *)
  105. (* DestroyDeque should be called when the deque is no longer needed   *)
  106. (* in memory.                                                         *)
  107.  
  108. PROCEDURE Full         (size: CARDINAL): BOOLEAN;
  109. (* Return TRUE if there is no Available memory for another deque node *)
  110.  
  111. PROCEDURE DequeLength  (deque: Deques): CARDINAL;
  112. (* Returns the number of nodes in the deque                           *)
  113.  
  114. PROCEDURE DequePos     (data: ARRAY OF BYTE; deque: Deques): CARDINAL;
  115. (* Returns the number of the node containing the data (if found).     *)
  116. (* Returns 0 if not found.  The front of the deque is treated as node *)
  117. (* number one.                                                        *)
  118.  
  119. PROCEDURE InDeque      (data: ARRAY OF BYTE; deque: Deques): BOOLEAN;
  120. (* Returns TRUE if data is found in deque.                            *)
  121.  
  122. PROCEDURE Enqueue      (data: ARRAY OF BYTE; VAR deque: Deques; VAR Ok: BOOLEAN);
  123. (* Place data in node at the back of the deque.  Ok will be set to    *)
  124. (* FALSE under the following conditions:  Deque is full.              *)
  125.  
  126. PROCEDURE Push         (data: ARRAY OF BYTE; VAR deque: Deques; VAR Ok: BOOLEAN);
  127. (* Place data in node at the back of the deque.  Ok will be set to    *)
  128. (* FALSE under the following conditions:  Deque is full.              *)
  129.  
  130. PROCEDURE Dequeue      (VAR data: ARRAY OF BYTE; VAR deque: Deques; VAR Ok: BOOLEAN);
  131. (* Place contents from node at the front of the deque into data.      *)
  132. (* Remove the front node of the deque.  Ok is set to FALSE upon the   *)
  133. (* following conditions:  deque is empty, size of data does not equal *)
  134. (* size of contents.                                                  *)
  135.  
  136. PROCEDURE Pop          (VAR data: ARRAY OF BYTE; VAR deque: Deques; VAR Ok: BOOLEAN);
  137. (* Place contents from node at the back of the deque into data.       *)
  138. (* Remove the back node of the deque.  Ok is set to FALSE upon the    *)
  139. (* following conditions:  deque is empty, size of data does not equal *)
  140. (* size of contents.                                                  *)
  141.  
  142. PROCEDURE Serve        (VAR data: ARRAY OF BYTE; nthItem: CARDINAL; VAR deque: Deques; VAR Ok: BOOLEAN);
  143. (* Place contents from nth node of the deque into data.  Remove the   *)
  144. (* nth node of the deque.  Ok is set to FALSE upon the following      *)
  145. (* conditions:  deque is empty, size of data does not equal size of   *)
  146. (* contents, nthItem is greater than number of nodes in the deque.    *)
  147.  
  148. PROCEDURE Front        (VAR data: ARRAY OF BYTE; deque: Deques; VAR Ok: BOOLEAN);
  149. (* Place contents from node at the front of the deque into data.      *)
  150. (* Ok is set to FALSE upon the following conditions:  deque is empty, *)
  151. (* size of data does not equal size of contents.                      *)
  152.  
  153. PROCEDURE Back         (VAR data: ARRAY OF BYTE; deque: Deques; VAR Ok: BOOLEAN);
  154. (* Place contents from node at the back of the deque into data.       *)
  155. (* Ok is set to FALSE upon the following conditions:  deque is empty, *)
  156. (* size of data does not equal size of contents.                      *)
  157.  
  158. PROCEDURE Top          (VAR data: ARRAY OF BYTE; deque: Deques; VAR Ok: BOOLEAN);
  159. (* Place contents from node at the back (top) of the deque into data. *)
  160. (* Ok is set to FALSE upon the following conditions:  deque is empty, *)
  161. (* size of data does not equal size of contents.                      *)
  162.  
  163. PROCEDURE Retrieve     (VAR data: ARRAY OF BYTE; nthItem: CARDINAL; deque: Deques; VAR Ok: BOOLEAN);
  164. (* Place contents from nth node of the deque into data.  Ok is set to *)
  165. (* FALSE upon the following conditions:  deque is empty, size of data *)
  166. (* does not equal size of contents.  nthItem is greater than number   *)
  167. (* of nodes in the deque.                                             *)
  168.  
  169. END PMPDeque.
  170.  
  171.  
  172. <-------------------------- cut here --------------------------------->
  173.  
  174.  
  175. (*====================================================================
  176.   =  Program Id:     PMPDEQUE                                        =
  177.   =  Programmer:     Peter M. Perchansky                             =
  178.   =  Purpose:        Export procedures for dealing deques.           =
  179.   =  Date Written:   10-29-89                                        =
  180.   ====================================================================*)
  181.  
  182. IMPLEMENTATION MODULE PMPDeque;
  183.  
  184. (*------------- Procedures from JPI's TopSpeed Modula II -------------*)
  185. FROM AsmLib   IMPORT Compare, Move;
  186. FROM SYSTEM   IMPORT ADDRESS, BYTE, TSIZE;
  187. FROM Storage  IMPORT ALLOCATE, Available, DEALLOCATE;
  188. (*--------------------------------------------------------------------*)
  189.  
  190. TYPE
  191.     Deques     = POINTER TO DequeNodes;  (* opaque type defined *)
  192.  
  193.     DequeNodes = RECORD                  (* node *)
  194.                    contents : ADDRESS;   (* contents of node *)
  195.                    size     : CARDINAL;  (* size of contents *)
  196.                    next     : Deques;    (* pointer to next node *)
  197.                    previous : Deques;    (* pointer to prev node *)
  198.                  END;
  199.  
  200.  
  201. (*--------------------------------------------------------------------*)
  202. (*          Utility procedures used internally by PMPDeque.           *)
  203. (*--------------------------------------------------------------------*)
  204.  
  205. PROCEDURE DeleteNode            (VAR node: Deques);
  206. (* Deletes specified node from deque                                  *)
  207.  
  208. VAR
  209.     nodeToDelete : Deques;             (* save pointer for deletion *)
  210.  
  211. BEGIN
  212.     IF node^.next = node THEN          (* Delete last node in deque *)
  213.        DEALLOCATE (node^.contents, node^.size);
  214.        DEALLOCATE (node, TSIZE (DequeNodes));
  215.        node := NIL;
  216.     ELSE
  217.        nodeToDelete := node;           (* Delete specified node     *)
  218.        node := node^.next;
  219.        nodeToDelete^.previous^.next := node;
  220.        node^.previous := nodeToDelete^.previous;
  221.        DEALLOCATE (nodeToDelete^.contents, nodeToDelete^.size);
  222.        DEALLOCATE (nodeToDelete, TSIZE (DequeNodes));
  223.     END;
  224. END DeleteNode;
  225.  
  226. PROCEDURE InsertNodeAtEnd       (node: Deques; VAR deque: Deques);
  227. (* Inserts specified node at end of deque                             *)
  228.  
  229. BEGIN
  230.     IF Empty (deque) THEN              (* create front *)
  231.        node^.next := node;
  232.        node^.previous := node;
  233.        deque := node;
  234.     ELSE                               (* add to end   *)
  235.        node^.next := deque;
  236.        node^.previous := deque^.previous;
  237.        deque^.previous^.next := node;
  238.        deque^.previous := node;
  239.     END;
  240. END InsertNodeAtEnd;
  241.  
  242.  
  243. (*--------------------------------------------------------------------*)
  244. (*          Procedures exported by PMPDeque.                          *)
  245. (*--------------------------------------------------------------------*)
  246.  
  247. PROCEDURE CreateDeque           (VAR deque: Deques);
  248. (* Creates the deque by making it NIL                                 *)
  249. (* This procedure must be called prior to performing operations on    *)
  250. (* the deque.                                                         *)
  251.  
  252. BEGIN
  253.     deque := NIL;
  254. END CreateDeque;
  255.  
  256. PROCEDURE Empty        (deque: Deques) : BOOLEAN;
  257. (* Return TRUE if the deque is NIL                                    *)
  258.  
  259. BEGIN
  260.     RETURN deque = NIL;
  261. END Empty;
  262.  
  263. PROCEDURE DestroyDeque (VAR deque: Deques);
  264. (* Destroys the deque by deallocating deque nodes and contents        *)
  265. (* DestroyDeque should be called when the deque is no longer needed   *)
  266. (* in memory.                                                         *)
  267.  
  268. BEGIN
  269.     WHILE NOT Empty (deque) DO
  270.           DeleteNode (deque);
  271.     END;
  272. END DestroyDeque;
  273.  
  274. PROCEDURE Full         (size: CARDINAL): BOOLEAN;
  275. (* Return TRUE if there is no Available memory for another deque node *)
  276.  
  277. BEGIN
  278.     RETURN (NOT (Available (TSIZE (DequeNodes)) AND Available (size)));
  279. END Full;
  280.  
  281. PROCEDURE DequeLength (deque : Deques) : CARDINAL;
  282. (* Returns the number of nodes in the deque                           *)
  283.  
  284. VAR
  285.     current : Deques;           (* cursor used to walk the deque *)
  286.     count   : CARDINAL;         (* node counter *)
  287.  
  288. BEGIN
  289.     count := 0;
  290.  
  291.     IF NOT Empty (deque) THEN
  292.        current := deque^.previous;        (* start from back of deque *)
  293.  
  294.        REPEAT
  295.              INC (count);
  296.              current := current^.next;    (* and walk forward until   *)
  297.        UNTIL current = deque^.previous;   (* we've reached the back   *)
  298.     END;
  299.  
  300.     RETURN count;
  301. END DequeLength;
  302.  
  303. PROCEDURE DequePos     (data: ARRAY OF BYTE; deque: Deques): CARDINAL;
  304. (* Returns the number of the node containing the data (if found).     *)
  305. (* Returns 0 if not found.  The front of the deque is treated as node *)
  306. (* number one.                                                        *)
  307.  
  308. VAR
  309.     count,                      (* node counter *)
  310.     pos      : CARDINAL;        (* returned from AsmLib.Compare  *)
  311.     current  : Deques;          (* cursor used to walk the deque *)
  312.  
  313. BEGIN
  314.     count := 0;
  315.     IF NOT Empty (deque) THEN
  316.        current := deque^.previous;    (* start from the back of deque *)
  317.  
  318.        REPEAT
  319.             INC (count);
  320.             current := current^.next;
  321.             pos := Compare (ADR (data), current^.contents, current^.size);
  322.        UNTIL (current = deque^.previous) OR (pos = current^.size);
  323.     END;
  324.  
  325.     IF pos = current^.size THEN        (* pos = size upon exact match *)
  326.        RETURN count
  327.     ELSE
  328.        RETURN 0
  329.     END;
  330. END DequePos;
  331.  
  332. PROCEDURE InDeque      (data: ARRAY OF BYTE; deque: Deques): BOOLEAN;
  333. (* Returns TRUE if data is found in deque.                            *)
  334.  
  335. BEGIN
  336.     RETURN (DequePos (data, deque) # 0);
  337. END InDeque;
  338.  
  339. PROCEDURE Enqueue      (data: ARRAY OF BYTE; VAR deque: Deques; VAR Ok: BOOLEAN);
  340. (* Place data in node at the back of the deque.  Ok will be set to    *)
  341. (* FALSE under the following conditions:  Deque is full.              *)
  342.  
  343. VAR
  344.     newNode     : Deques;       (* used to create new node *)
  345.     dataSize    : CARDINAL;     (* size of data *)
  346.  
  347. BEGIN
  348.     dataSize := HIGH (data) + 1;
  349.     Ok := NOT Full (dataSize);
  350.  
  351.     IF Ok THEN
  352.        ALLOCATE (newNode, TSIZE (DequeNodes));
  353.        ALLOCATE (newNode^.contents, dataSize);
  354.  
  355.        Move (ADR (data), newNode^.contents, dataSize);
  356.        newNode^.size := dataSize;
  357.        InsertNodeAtEnd (newNode, deque);
  358.     END;
  359. END Enqueue;
  360.  
  361. PROCEDURE Push         (data: ARRAY OF BYTE; VAR deque: Deques; VAR Ok: BOOLEAN);
  362. (* Place data in node at the back of the deque.  Ok will be set to    *)
  363. (* FALSE under the following conditions:  Deque is full.              *)
  364.  
  365. BEGIN
  366.     Enqueue (data, deque, Ok);
  367. END Push;
  368.  
  369. PROCEDURE Dequeue      (VAR data: ARRAY OF BYTE; VAR deque: Deques; VAR Ok: BOOLEAN);
  370. (* Place contents from node at the front of the deque into data.      *)
  371. (* Remove the front node of the deque.  Ok is set to FALSE upon the   *)
  372. (* following conditions:  deque is empty, size of data does not equal *)
  373. (* size of contents.                                                  *)
  374.  
  375. VAR
  376.     dataSize    : CARDINAL;     (* size of data *)
  377.  
  378. BEGIN
  379.     Ok := NOT Empty (deque);
  380.     IF Ok THEN
  381.        dataSize := HIGH (data) + 1;
  382.  
  383.        Ok := deque^.size = dataSize;
  384.  
  385.        (* size of data must equal the size of contents *)
  386.  
  387.        IF Ok THEN
  388.           Move (deque^.contents, ADR (data), deque^.size);
  389.           DeleteNode (deque);
  390.        END;
  391.     END;
  392. END Dequeue;
  393.  
  394. PROCEDURE Pop          (VAR data: ARRAY OF BYTE; VAR deque: Deques; VAR Ok: BOOLEAN);
  395. (* Place contents from node at the back of the deque into data.       *)
  396. (* Remove the back node of the deque.  Ok is set to FALSE upon the    *)
  397. (* following conditions:  deque is empty, size of data does not equal *)
  398. (* size of contents.                                                  *)
  399.  
  400. VAR
  401.   dataSize   : CARDINAL;        (* size of data *)
  402.  
  403. BEGIN
  404.     Ok := NOT Empty (deque);
  405.     IF Ok THEN
  406.        dataSize := HIGH (data) + 1;
  407.  
  408.        IF deque^.next = deque THEN          (* only one node *)
  409.           Ok := deque^.size = dataSize;
  410.  
  411.           (* size of data must equal size of contents *)
  412.  
  413.           IF Ok THEN
  414.              Move (deque^.contents, ADR (data), deque^.size);
  415.              DeleteNode (deque);
  416.           END;
  417.        ELSE
  418.           Ok := deque^.previous^.size = dataSize;
  419.  
  420.           (* size of data must equal size of contents *)
  421.  
  422.           IF Ok THEN
  423.              Move (deque^.previous^.contents, ADR (data), deque^.previous^.size);
  424.              DeleteNode (deque^.previous);
  425.           END;
  426.        END;
  427.     END;
  428. END Pop;
  429.  
  430. PROCEDURE Serve        (VAR data: ARRAY OF BYTE; nthItem: CARDINAL; VAR deque: Deques; VAR Ok: BOOLEAN);
  431. (* Place contents from nth node of the deque into data.  Remove the   *)
  432. (* nth node of the deque.  Ok is set to FALSE upon the following      *)
  433. (* conditions:  deque is empty, size of data does not equal size of   *)
  434. (* contents, nthItem is greater than number of nodes in the deque.    *)
  435.  
  436. VAR
  437.     current        : Deques;    (* used to walk the deque *)
  438.     dataSize,                   (* size of data *)
  439.     numberOfNodes,              (* length of deque *)
  440.     count          : CARDINAL;  (* node counter *)
  441.  
  442. BEGIN
  443.     Ok := NOT Empty (deque);
  444.     IF Ok THEN
  445.        numberOfNodes := DequeLength (deque);
  446.  
  447.        Ok := (nthItem <= numberOfNodes) AND (nthItem > 0);
  448.  
  449.        (* nthItem must be less than length of deque & greater than 0 *)
  450.  
  451.        IF Ok THEN
  452.           dataSize := HIGH (data) + 1;
  453.  
  454.           count := 0;
  455.           current := deque^.previous;      (* start from back of deque *)
  456.  
  457.           REPEAT
  458.                 INC (count);               (* walk from back until we  *)
  459.                 current := current^.next;  (* have the nth Item        *)
  460.           UNTIL count = nthItem;
  461.  
  462.           Ok := current^.size = dataSize;
  463.  
  464.           (* size of contents must equal size of data *)
  465.  
  466.           IF Ok THEN
  467.              Move (current^.contents, ADR (data), current^.size);
  468.  
  469.              IF count = 1 THEN
  470.                 DeleteNode (deque)
  471.              ELSE
  472.                 DeleteNode (current)
  473.              END;
  474.           END;
  475.        END;
  476.     END;
  477. END Serve;
  478.  
  479. PROCEDURE Front        (VAR data: ARRAY OF BYTE; deque: Deques; VAR Ok: BOOLEAN);
  480. (* Place contents from node at the front of the deque into data.      *)
  481. (* Ok is set to FALSE upon the following conditions:  deque is empty, *)
  482. (* size of data does not equal size of contents.                      *)
  483.  
  484. VAR
  485.     dataSize : CARDINAL;        (* size of data *)
  486.  
  487. BEGIN
  488.     Ok := NOT Empty (deque);
  489.     IF Ok THEN
  490.        dataSize := HIGH (data) + 1;
  491.        Ok := deque^.size = dataSize;
  492.  
  493.        (* size of data must equal size of contents *)
  494.  
  495.        IF Ok THEN
  496.           Move (deque^.contents, ADR (data), deque^.size);
  497.        END;
  498.     END;
  499. END Front;
  500.  
  501. PROCEDURE Back         (VAR data: ARRAY OF BYTE; deque: Deques; VAR Ok: BOOLEAN);
  502. (* Place contents from node at the back of the deque into data.       *)
  503. (* Ok is set to FALSE upon the following conditions:  deque is empty, *)
  504. (* size of data does not equal size of contents.                      *)
  505.  
  506. VAR
  507.     dataSize : CARDINAL;        (* size of data *)
  508.  
  509. BEGIN
  510.     Ok := NOT Empty (deque);
  511.     IF Ok THEN
  512.        dataSize := HIGH (data) + 1;
  513.  
  514.        Ok := deque^.previous^.size = dataSize;
  515.  
  516.        (* size of data must equal size of contents *)
  517.  
  518.        IF Ok THEN
  519.           Move (deque^.previous^.contents, ADR (data), deque^.previous^.size);
  520.        END;
  521.     END;
  522. END Back;
  523.  
  524. PROCEDURE Top          (VAR data: ARRAY OF BYTE; deque: Deques; VAR Ok: BOOLEAN);
  525. (* Place contents from node at the back (top) of the deque into data. *)
  526. (* Ok is set to FALSE upon the following conditions:  deque is empty, *)
  527. (* size of data does not equal size of contents.                      *)
  528.  
  529. BEGIN
  530.     Back (data, deque, Ok);
  531. END Top;
  532.  
  533. PROCEDURE Retrieve     (VAR data: ARRAY OF BYTE; nthItem: CARDINAL; deque: Deques ; VAR Ok: BOOLEAN);
  534. (* Place contents from nth node of the deque into data.  Ok is set to *)
  535. (* FALSE upon the following conditions:  deque is empty, size of data *)
  536. (* does not equal size of contents.  nthItem is greater than number   *)
  537. (* of nodes in the deque.                                             *)
  538.  
  539. VAR
  540.     current        : Deques;    (* used to walk the deque *)
  541.     dataSize,                   (* size of data *)
  542.     numberOfNodes,              (* length of deque *)
  543.     count          : CARDINAL;  (* node counter *)
  544.  
  545. BEGIN
  546.     Ok := NOT Empty (deque);
  547.     IF Ok THEN
  548.        numberOfNodes := DequeLength (deque);
  549.  
  550.        Ok := (nthItem <= numberOfNodes) AND (nthItem > 0);
  551.  
  552.        (* nthItem must be less than length of deque & greater than 0 *)
  553.  
  554.        IF Ok THEN
  555.           dataSize := HIGH (data) + 1;
  556.  
  557.           count := 0;
  558.           current := deque^.previous;      (* start from back of deque *)
  559.  
  560.           REPEAT
  561.                 INC (count);               (* walk from back until we  *)
  562.                 current := current^.next;  (* have the nth Item        *)
  563.           UNTIL count = nthItem;
  564.  
  565.           Ok := current^.size = dataSize;
  566.  
  567.           (* size of contents must equal size of data *)
  568.  
  569.           IF Ok THEN
  570.              Move (current^.contents, ADR (data), current^.size);
  571.           END;
  572.        END;
  573.     END;
  574. END Retrieve;
  575.  
  576. END PMPDeque.
  577.