Please send questions to st10@humboldt.edu .
//---------------------------------------------------------------------
// File: queue.template
// Name: Sharon M. Tuttle
// last modified: 4-01-05
//
// Template class name: queue
//
// Description: a collection of items such that entries can be
//    inserted at one end (called the rear) and removed at the
//    other end (called the front).
//    This version does NOT have a fixed capacity.
// 
// Implementation notes: 
//     * uses a linked list of elements of the node template class
//     * if there is insufficient dynamic memory, then the
//       following methods throw bad_alloc: enqueue
//---------------------------------------------------------------------

#include <cassert> // provides assert
#include <iostream>
//
// note: because this is a template class, it is included
//    in the header file (at the bottom), and not compiled
//    separately. Thus, the header file is not included here!
//
#include "node.h"
using namespace std;

/*****************************************************/
/* CONSTRUCTORS and DESTRUCTOR                       */
/*****************************************************/

// constructor
//
// postcondition: creates an empty queue instance
//
template <typename Item>
queue<Item>::queue()
{
    used = 0;
    front = NULL;
    rear = NULL;
}

// copy constructor 
//
// adapted from list_copy, Savitch and Main
//
template <typename Item>
queue<Item>::queue(const queue<Item>& source)
{
    node<Item> *source_curr, *new_curr;

    // start copy out as empty, but with the same value of used
    //    as the source being copied
    front = NULL;
    rear = NULL;
    used = source.used;

    // handle the case of the empty queue
    if (source.front == NULL)
    {
        return; // source is empty, so this copy is, too
    }

    // if source is NOT empty, make a copy of it

    // cause new copy to now have source front's data;
    front = new node<Item>(source.front->get_data());

    // start a pointer walking through the new copy
    //    starting from its front
    new_curr = front;

    // is there another in the source left to be copied?
    source_curr = source.front->get_next();

    // while there is another node in the source left
    //     to be copied...
    while (source_curr != NULL)
    {
        // add a new node to the new copy with the data in
        //    that node;
        new_curr->set_next(new node<Item>(source_curr->get_data()));

        // move the new copy's pointer to the new node
        new_curr = new_curr->get_next();

        // WHAT IF we're at the source's rear? Let's set 
        //    copy's rear, too, at that point;
        if (course_curr == source.rear)
        {
            rear = new_curr;
        }

        // is there another in the source left to be copied?
        source_curr = source_curr->get_next();
    }
}

// destructor 
//
template <typename Item>
queue<Item>::~queue()
{
    node<Item> *curr_ptr, *node_to_delete;

    curr_ptr = front;

    // need to deallocate EACH node in the queue
    while (curr_ptr != NULL)
    {
        node_to_delete = curr_ptr;
        curr_ptr = curr_ptr->get_next();
        delete node_to_delete;
    }

    // playing it safe...
    front = NULL;
    rear = NULL;
    used = 0;
}


/*************************************************************/
/* ACCESSORS and other constant member functions (observers) */
/*************************************************************/

// is_empty
//
// postcondition: returns true if queue is empty, and
//    returns false otherwise
//
template <typename Item>
bool    queue<Item>::is_empty( ) const
{
    return (used == 0);
}

// get_front
//
// precondition: is_empty() == false
//
// postcondition: returns the value of the front item of the
//    queue, BUT the queue is unchanged.
//
template <typename Item>
Item    queue<Item>::get_front( ) const
{
    assert(is_empty() == false);

    return(front->get_data());
}

/*****************************************************/
/* MODIFIERS and other modifying member functions    */
/*****************************************************/

// enqueue
//
// postcondition: a new copy of entry has been enqueueed
//    onto the (rear of the) queue
//
template <typename Item>
void    queue<Item>::enqueue(const Item& entry)
{
    node<Item> *temp;

    temp = new node<Item>(entry);

    // what if I am trying to enqueue onto an empty queue?
    if (rear == NULL)
    {
        front = temp;  // we have a new front in this case, too!
    }

    else
    {
        // old rear element's next field needs to point 
        //    to "new" rear element
        rear->set_next(temp);
    }

    // in EITHER case, now, rear can safely be made to
    //    point to the new rear element
    rear = temp;

    used++;
}

// dequeue
//
// precondition: is_empty() == false
//
// postcondition: the front item of the queue has been
//    removed, and its value is returned
//
template <typename Item>
Item   queue<Item>::dequeue( )
{
    value_type dequeued_item;
    node<Item>*      temp;

    assert(is_empty() == false);

    used--;

    // remember: if we reach here, we KNOW that queue is
    //    not empty

    dequeued_item = front->get_data();

    // keep track of item to be removed
    temp = front;

    // now it should be safe to make front point to the
    //    new front element
    front = front->get_next();

    // what if queue is empty? then need to set rear to NULL,
    //    too. (and queue is empty if front is NOW null...)
    if (front == NULL)
    {
        rear = NULL;
    }

    // free the space for this dequeued node from the heap,
    //    so it be be re-allocated for other uses
    delete temp;

    return dequeued_item;
}