Please send questions to st10@humboldt.edu .
//---------------------------------------------------------------------
// File: queue.template
// Name: Sharon M. Tuttle
// last modified: 2-1-05
//
// Template class name: queue
//
// Purpose: 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).
// 
// Implementation notes: 
//     * uses a dynamically-allocated array
//     * if there is insufficient dynamic memory, then the
//       following methods throw bad_alloc: enqueue
//---------------------------------------------------------------------

#include <cassert> // provides assert
//
// 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!
//
using namespace std;

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

// constructor
//
// postcondition: creates an empty queue instance
//
template <typename Item>
queue<Item>::queue()
{
    data = new Item[DEFAULT_CAPACITY];
    capacity = DEFAULT_CAPACITY;
    used = 0;
    first = 0;
    last = capacity - 1;    // first element enqueued should go in 0...
}

// copy constructor (because am using a pointer to
//    point to an array, so that array can be replaced with
//    a larger one as needed.
//
template <typename Item>
queue<Item>::queue(const queue<Item>& source)
{
    data = new Item[source.capacity];
    capacity = source.capacity;
    used = source.used;

    // copy over all array contents (so a "real" copy);
    //    some may be junk, but with a circular queue,
    //    "real" data may not start at 0...!
    for (int i=0; i<capacity; i++)
    {
        data[i] = source[i];
    }

    first = source.first;
    last = source.last;
}

// destructor (because am using a pointer to point to
//    an array, so that array can be replaced with a
//    larger one as needed.
//
template <typename Item>
queue<Item>::~queue()
{
    delete [] data;
}


/*************************************************************/
/* 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(data[first]);
}

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

// enqueue
//
// postcondition: a new copy of entry has been inserted
//    at the rear of the queue
//
template <typename Item>
void    queue<Item>::enqueue(const Item& entry)
{
    Item *larger_data;	// IF need to create new, larger array
    int  old_capacity;

    if (used == capacity)
    {
        old_capacity = capacity;
        capacity += queue<Item>::INCR_AMT;

        larger_data = new Item[capacity];
        
        // ouch -- this is the tricky part;
        //    Need to restart circular array so goes from
        //    0 to (used-1) in new bigger array, else
        //    next inserts will nuke first...!
        //
        for (int i=0, next=first; i < used; i++, next = (next + 1) % old_capacity)
        {
            larger_data[i] = data[next];
        }

        // now first and last must be reset, too; first is now
        //    0, last is now (used-1)
        first = 0;
        last = used-1;

        // release the memory data currently pointing to
        delete [ ] data;

        // now make data point to the new, bigger array
        data = larger_data;
    }

    // use modulo arithmetic, so "wrap" index when reach end 
    //    of array
    last = (last + 1) % capacity;

    data[last] = entry;
    used++;
}

// dequeue
//
// precondition: is_empty() == false
//
// postcondition: the front item of the queue has been
//    removed, and a reference to it is returned
//
template <typename Item>
Item&   queue<Item>::dequeue( )
{
    int old_first;

    assert(is_empty() == false);

    old_first = first;

    // use modulo arithmetic, so "wrap" index when reach end 
    //    of array
    first = (first + 1) % capacity;

    used--;

    return data[old_first];
}