PreviousUpNext

15.4.999  src/lib/src/rw-queue.pkg

## rw-queue.pkg
#
# See comments in    src/lib/src/rw-queue.api

# Compiled by:
#     src/lib/std/standard.lib

stipulate

herein

    package   rw_queue  
    : (weak)  Rw_Queue                                                                                  # Rw_Queue              is from   src/lib/src/rw-queue.api
    {
        Rw_Queue(X) = RW_QUEUE  { front:  Ref( List(X) ),                                               # Simple queue using the usual trick of adding to the input list,    
                                  back:   Ref( List(X) )                                                # removing from the output list, and when the output list is empty,  
                                };                                                                      # reversing the input list and making it the output list.
                                                                                                        # A nice simple algorithm where both push and pull are O(1).

        fun reverse (x,       [], rl) =>  (x, rl);
            reverse (x, y ! rest, rl) =>  reverse (y, rest, x ! rl);
        end;

        fun reverse_and_prepend (      [], l) =>  l;
            reverse_and_prepend (x ! rest, l) =>  reverse_and_prepend (rest, x ! l);
        end;

        fun make_rw_queue ()
            =
            RW_QUEUE  { front =>  REF [],
                        back  =>  REF []
                      };

        fun same_queue ( RW_QUEUE { front=> refcell1, ... },
                         RW_QUEUE { front=> refcell2, ... }
                       )
            =
            refcell1 == refcell2;                                                                       # Taking advantage of the fact that refcells are equal only to themselves and thus uniquely identify a queue.

        fun queue_is_empty (RW_QUEUE { front => REF [],
                                       back  => REF []
                                     }
                           )
                                =>   TRUE;
            queue_is_empty _    =>   FALSE;
        end;


        fun put_on_back_of_queue (RW_QUEUE { back, ... }, item)
            =
            back :=  item  !  *back;


        fun put_on_front_of_queue (RW_QUEUE { front, ... }, item)                                       # We occasionally use this when a thread needs to run immediately.
            =
            front :=  item  !  *front;


        fun take_from_front_of_queue_or_raise_exception (RW_QUEUE { front, back } )
            =
            case *front
                #
                (x ! rest)
                    =>
                    {   front := rest;
                        x;
                    };

                [] =>   case *back
                            #
                            (x ! rest)
                                =>
                                {   (reverse (x, rest, [])) ->   (y, rr);
                                    #   
                                    front := rr;
                                    back  := [];
                                    y;
                                    #   
                                };

                            [] =>  raise exception  DIE "queue is empty";
                        esac;

            esac;


        fun take_from_front_of_queue (RW_QUEUE { front, back } )                        # Normal case.
            =
            case *front
                #
                (x ! rest) =>   {   front :=  rest;
                                    #
                                    THE x;
                                };

                []  =>          case *back
                                    #
                                    (x ! rest) =>   {   (reverse (x, rest, []))
                                                            ->
                                                            (y, rr);

                                                        front := rr;
                                                        back  := [];
                                                        # 
                                                        THE y;
                                                    };

                                    []         =>   NULL;
                                esac;
            esac;


        fun take_from_back_of_queue (RW_QUEUE { front, back } )                         # Abnormal case included only for completeness -- currently unused.  -- 2012-03-28 CrT
            =                                                                           # This is the exact reverse of the above fn.
            case *back
                #
                (x ! rest) =>   {   back :=  rest;
                                    #
                                    THE x;
                                };

                []  =>          case *front
                                    #
                                    (x ! rest) =>   {   (reverse (x, rest, []))
                                                            ->
                                                            (y, rr);

                                                        back  := rr;
                                                        front := [];
                                                        # 
                                                        THE y;
                                                    };

                                    []         =>   NULL;
                                esac;
            esac;


        fun clear_queue_to_empty (RW_QUEUE { front, back } )
            =
            {   front := [];
                back  := [];
            };


        fun to_list (RW_QUEUE { back, front } )
            =
            (*front @ (list::reverse *back));

        # For debug and unit testing:
        #
        fun frontq (RW_QUEUE { front, ... }) =  *front;
        fun  backq (RW_QUEUE {  back, ... }) =  *back;


        fun find_first_matching_item_and_remove_from_queue
              (
                RW_QUEUE { front, back },
                predicate
              )
            =
            remove_from_front (*front, [])
            where
                fun remove_from_front ([], l)
                        =>
                        remove_from_back (*back, []);

                    remove_from_front (x ! rest, l)
                        =>
                        if (predicate x)        {   front := reverse_and_prepend (l, rest);
                                                    THE x;
                                                };      
                        else                    remove_from_front (rest, x ! l);
                        fi;
                end 

                also
                fun remove_from_back ([], _) =>   NULL;
                    #
                    remove_from_back (x ! rest, l)
                        =>
                        if (predicate x)        {   back := reverse_and_prepend (l, rest);
                                                    THE x;
                                                };
                        else                    remove_from_back (rest, x ! l);
                        fi;
                end;
            end;


        # Some synonyms:
        #
        push = put_on_back_of_queue;
        pull = take_from_front_of_queue;
        #
        unpull = put_on_front_of_queue;
        unpush = take_from_back_of_queue;
    };
end;


Comments and suggestions to: bugs@mythryl.org

PreviousUpNext