packages feed

language-Modula2-0.1: examples/Modula-2_Libraries/andrea-m2/lib/generic/queues.mod

IMPLEMENTATION MODULE Queues;

(* Procedures for non-homogeneous multi-direction queue data structure *)
(* John Andrea, Oct.11/91 *)
(* This code may be freely used and distributed, it may not be sold. *)

FROM SYSTEM IMPORT BYTE;
FROM MoreMath IMPORT MinCard;
FROM Storage  IMPORT ALLOCATE, DEALLOCATE;

CONST
   max_data   = 511;

TYPE
   DataPtr   = POINTER TO QueueData;
   QueueData = RECORD
                 data        :ARRAY [0..max_data] OF BYTE;
                 size        :CARDINAL;
                 top, bottom :DataPtr;
               END;

   Queue     = POINTER TO AQueue;
   AQueue    = RECORD
                 top, bottom :DataPtr;
                 n           :CARDINAL;
               END;

VAR
   q      :DataPtr;
   max, i :CARDINAL;

   (* ------------------------------------------- *)
   PROCEDURE InitQueue( VAR a_queue :Queue );
   (* Create a queue, this must be called before the queue is used *)
   BEGIN

     NEW( a_queue );
     a_queue^.n      := 0;
     a_queue^.top    := NIL;
     a_queue^.bottom := NIL;

   END InitQueue;

   (* ------------------------------------------- *)
   PROCEDURE Push( a_queue :Queue; which_end :Directions; data :ARRAY OF BYTE );
   (* Push an item onto the queue *)
   BEGIN

     NEW( q );

     max     := MinCard( HIGH(data), max_data );
     q^.size := max;

     FOR i := 0 TO max DO
        q^.data[i] := data[i];
     END;

     (* and setup the correct pointers *)

     a_queue^.n := a_queue^.n + 1;

     IF a_queue^.n = 1 THEN

       q^.top          := NIL;
       q^.bottom       := NIL;

       (* this is the only item on the queue, top and bottom are same place *)
       a_queue^.top    := q;
       a_queue^.bottom := q;

     ELSE

       IF which_end = Top THEN

         q^.top    := NIL;
         q^.bottom := a_queue^.top;

         (* the new item is the top of the old top *)
         a_queue^.top^.top := q;

         (* the new item is the new top *)
         a_queue^.top := q;

       ELSE

         q^.top    := a_queue^.bottom;
         q^.bottom := NIL;

         (* the new item is the bottom of the old bottom *)
         a_queue^.bottom^.bottom := q;

         (* the new item is the new bottom *)
         a_queue^.bottom := q;

       END;
     END;

   END Push;

   (* ------------------------------------------- *)
   PROCEDURE Pop( a_queue :Queue; which_end :Directions;
                  VAR data :ARRAY OF BYTE; VAR nothing_to_pop :BOOLEAN );
   (* Get an item from the queue *)
   BEGIN

     IF a_queue^.n = 0 THEN
       nothing_to_pop := TRUE;
     ELSE
       nothing_to_pop := FALSE;

       IF which_end = Top THEN
         q := a_queue^.top;
       ELSE
         q := a_queue^.bottom;
       END;

       (* move the data *)

       max := MinCard( HIGH(data), q^.size );
       FOR i := 0 TO max DO
          data[i] := q^.data[i];
       END;

       (* reset the pointers *)

       a_queue^.n := a_queue^.n - 1;

       IF a_queue^.n = 0 THEN
         (* nothing left in the queue, set both top and bottom to empty *)
         a_queue^.top    := NIL;
         a_queue^.bottom := NIL;

       ELSE

         IF which_end = Top THEN
           a_queue^.top := q^.bottom;
         ELSE
           a_queue^.bottom := q^.top;
         END;

       END;

       (* get rid of the item which was just pop'ed *)

       DISPOSE( q );

     END;

   END Pop;

   (* ------------------------------------------- *)
   PROCEDURE DelQueue( VAR a_queue :Queue );
   (* Complete delete a queue *)
   BEGIN

      WHILE a_queue^.top # NIL DO
         q := a_queue^.top^.bottom;
         DISPOSE( a_queue^.top );
         a_queue^.top := q;
      END;

      DISPOSE( a_queue );

   END DelQueue;

   (* ------------------------------------------- *)
   PROCEDURE QueueInfo( a_queue :Queue; which_end :Directions;
                        VAR n_items, size :CARDINAL );
   (* Return some info about a queue *)
   BEGIN

     n_items := a_queue^.n;
     IF n_items = 0 THEN
       size := 0;
     ELSE

       IF which_end = Top THEN
         size := a_queue^.top^.size;
       ELSE
         size := a_queue^.bottom^.size;
       END;

       size := size + 1; (* to account for the zero offset *)

     END;

   END QueueInfo;

BEGIN
END Queues.