Please send questions to st10@humboldt.edu .
//-----------------------------------------------------------
// File: set.template
// Name: Michael Main, Walter Savitch
//       (adapted by Sharon M. Tuttle)
// last modified: 4-27-05
//
// Class implemented: set (see set.h for documentation)
//                    (a container template class for a collection of 
//                     items with NO duplicates)
//
// INVARIANT for the set template class:
//   1. The number of items in the set is in the 
//      member variable used;
//   2. The actual items of the set are stored in a partially 
//      filled array. The array is a dynamic array, pointed to 
//      by the member variable data;
//   3. The size of the dynamic array is in the member 
//      variable capacity.
//   4. If there is a current item, then current_index lies in the
//      range of [0 .. used-1]; otherwise, current_index == used.
//--------------------------------------------------------------

#include <algorithm>     // Provides copy function
#include <cassert>       // Provides assert function
#include "set.h"
using namespace std;

// (note that the following is required for the named constant)
//
//template <typename Item>
//const typename size_t set<Item>::DEFAULT_CAPACITY;

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

// postcondition: creates an empty set instance with an 
//    initial capacity of DEFAULT_CAPACITY
//
template <typename Item>
set<Item>::set()
{
    data = new Item[DEFAULT_CAPACITY];
    capacity = DEFAULT_CAPACITY;
    used = 0;

    current_index = used;
}

// postcondition: creates an empty set instance with an 
//    initial capacity of initial_capacity
//
template <typename Item>
set<Item>::set(size_t initial_capacity)
{
    data = new Item[initial_capacity];
    capacity = initial_capacity;
    used = 0;

    current_index = used;
}

// Copy constructor
//
// Library facilities used: algorithm
//
template <typename Item>
set<Item>::set(const set<Item>& source)
{
    data = new Item[source.capacity];
    capacity = source.capacity;
    used = source.used;

    // (copy is from the algorithm library)
    copy(source.data, source.data + used, data);

    // in the spirit (I think) of the discussion on the course
    //    text, p. 297, the copy's iterator will NOT be
    //    set (user needs to call start( ) for the copy
    //    to start up an iteration)
    current_index = used;
}

// destructor
//
template <typename Item>
set<Item>::~set( )
{
    delete [ ] data;
}

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

// get_size
//
// postcondition: returns the number of items in the set.
// 
template <typename Item>
size_t set<Item>::get_size( ) const 
{ 
        return used; 
}

// contains
//
// postcondition: returns true if the target is in the set,
//    and returns false if it is not.
// 
//
template <typename Item>
bool set<Item>::contains(const value_type& target) const
{
    size_t i;

    // check each item of set, seeing if it is the target;
    //    (if it is, we are DONE, the set DOES contain the
    //    target!)
    for (i = 0; i < used; i++)
    {
        if (target == data[i])
        {
            return true;
        }
    }

    // IF reach here, target was not found in set
    //    (otherwise, we would have returned from inside
    //    the loop)
    return false;
}

// get_curr_capacity
//
// postcondition: returns the current capacity of this 
//    set 
//
template <typename Item>
size_t set<Item>::get_curr_capacity() const 
{
    return capacity;
}
        
// is_item
//
// postcondition: returns true if there is a valid "current"
//     item that may be returned by the current member function.
//     Returns false if there is no valid current item.
//
template <typename Item>
bool set<Item>::is_item() const
{
    return (current_index != used);
}

// current
//
// precondition: is_item() == true
// postcondition: returns the current item in the set's
//     internal iterator.
//
//
template <typename Item>
Item set<Item>::current() const
{
    assert(is_item() == true);

    return data[current_index];
}


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

// insert
//
// postcondition: if entry is not already in the set,
//    then add it to the set; otherwise, set is unchanged.
//
template <typename Item>
void set<Item>::insert(const value_type& entry)
{   
    // if entry is already in the set, we're done;
    //    no change is required.
    if (contains(entry))
    {
        return;
    }

    // IF reach here, entry is NOT in set, and should be
    //    added.

    // increase set's capacity if necessary
    if (used == capacity)
    {
        reserve(used+1);
    }

    data[used] = entry;
    used++;

    // in the spirit of the discussion on p.297 of Savitch
    //    and Main, the iterator should probably become
    //    invalid when the container changes (because of
    //    this insertion, in this case). 
    // Now, if there WAS no current iteration going on,
    //    we'd need to make sure that the class invariant
    //    held by assigning (the new) used to current_index.
    // BUT, given the p.297 discussion, we'd want to make
    //    a current iteration --- IF there was one ---
    //    invalid. And how would we do that? By setting
    //    current_index to used!
    // SO... in EITHER case:

    current_index = used;
}

// remove
//
// postcondition: if target was in the set, remove it and
//    return true; otherwise, return false (and the set is
//    unchanged)
//
template <typename Item>
bool set<Item>::remove(const value_type& target)
{
    size_t index; // The location of target in the data array    

    // First, set index to the location of target in the data 
    //    array, which could be as small as 0 or as large as used-1.
    //    If target is not in the array, then index will be set 
    //    equal to used.
    index = 0;
        
    while ((index < used) && (data[index] != target))
    {
        index++;
    }

    // if target isn't in the set, then there's no work to do
    if (index == used) 
    {
        return false;
    }
        
    // IF execution reaches here, target is in the set at 
    //    data[index]. So, reduce used by 1 and copy the 
    //    last item onto data[index].
    used--;
    data[index] = data[used];

    // in the spirit of the discussion on p.297 of Savitch
    //    and Main, the iterator should probably become
    //    invalid when the container changes (because of
    //    this removal, in this case). 
    // Now, if there WAS no current iteration going on,
    //    we'd need to make sure that the class invariant
    //    held by assigning (the new) used to current_index.
    // BUT, given the p.297 discussion, we'd want to make
    //    a current iteration --- IF there was one ---
    //    invalid. And how would we do that? By setting
    //    current_index to used!
    // SO... in EITHER case:

    current_index = used;

    // and, if reach here --- DID remove an item from set, so:
    return true;
}

// reserve
//
// postconditions:
//    *   if new_capacity < used, set's capacity is
//        changed to used (will not make the capacity
//        less than the number of items already in 
//        the set).
//    *   otherwise, the set's current capacity is 
//        changed to new_capacity.
//
// Library facilities used: algorithm
//
template <typename Item>
void set<Item>::reserve(size_t new_capacity)
{
    Item *larger_array;

    // if allocated memory is already the right size, we're done;
    if (new_capacity == capacity)
    {
        return; 
    }

    // WILL let capacity of set be reduced, but NOT
    //    any smaller than current number of items.
    if (new_capacity < used)
    {
        // can't allocate less than we are using
        new_capacity = used;
    }

    // allocate new array and copy over set items
    larger_array = new value_type[new_capacity];
    copy(data, data + used, larger_array); // from algorithm library

    // (notice that we are freeing the "old" array...)
    delete [ ] data;

    data = larger_array;
    capacity = new_capacity;
}

// start
//
// postcondition: one of the items in the set becomes 
//     the current item (but if the set is empty, there
//     is no current item)
//
template <typename Item>
void set<Item>::start()
{
    if (get_size() == 0)
    {
        return;      // if set is empty, there is no current item
    }
    else
    {
        // note that, given the definition of a set, I could
        //    start the internal iterator wherever I want ---
        //    but I'm making it easy and starting at index 0.
        current_index = 0;
    }
}

// advance
//
// precondition: is_item() == true
// postcondition: if the current item is the last in the
//     set's internal iterator, then there is no longer
//     any current item. Otherwise, the new current item
//     is another set element that has not yet been current
//     during this internal iterator.
//
template <typename Item>
void set<Item>::advance()
{
    assert(is_item() == true);

    // have we already "seen" all of the items in the current
    //    internal iterator? If so, then there is no longer
    //    any current item.
    if (current_index == (used-1))
    {
        current_index = used;   // see set invariant #4
                                //    (yes, I COULD have just added
                                //    one here, too. Maybe I should
                                //    have. But I want to make the
                                //    point that with a different
                                //    invariant, this COULD be a
                                //    separate case.)
    }
    
    // otherwise, we'd like the new current item to be another
    //    set element that has not yet been current during this
    //    internal iterator. Keeping this simple, then:
    else
    {
        current_index++;
    }
}

/****************************************************/
/* OVERLOADED OPERATORS                             */
/****************************************************/

// +=
//
// postcondition: for each item in addend:
//    *   if that item is not already in this set, it is
//        added to this set.
//    *   if that item is already in this set, then 
//        this set is unchanged.
//
// Library facilities used: algorithm
//
template <typename Item>
void set<Item>::operator +=(const set<Item>& addend)
{
    size_t i;

    // increase set capacity if necessary
    if (used + addend.used > capacity)
    {
        reserve(used + addend.used);
    }
        
    // should ONLY add addend items to set if they
    //    are not already there; but operation insert
    //    DOES check for this (and it will update used
    //    appropriately, too! 8-) )
    for (i=0; i<addend.used; i++)
    {
        insert(addend.data[i]);
    }

    //  we just changed used, so we need to again make sure that
    //    current_index still == used;
    // AND, in the spirit of Savitch and Main p. 297, we should
    //    probably invalidate any current iteration in the
    //    face of this change to the container; so, in either
    //    case:
    current_index = used;
}

// =
//
// postcondition: the set that activated this function
//    has the same items and capacity as source.
//
// Library facilities used: algorithm
//
template <typename Item>
void set<Item>::operator =(const set<Item>& source)
{
    value_type *new_data;

    // Check for possible self-assignment:
    if (this == &source)
    {
        return;
    }

    // If needed, allocate an array with a different size:
    if (capacity != source.capacity)
    { 
        new_data = new value_type[source.capacity];
        delete [ ] data;
        data = new_data;
        capacity = source.capacity;
    }

    // Copy the data from the source array:
    used = source.used;
    copy(source.data, source.data + used, data); // from algorithm lib

    //  we just (maybe) changed used, so we need to again make sure that
    //    current_index still == used;
    // AND, in the spirit of Savitch and Main p. 297, we should
    //    probably invalidate any current iteration in the
    //    face of this change to the container; so, in either
    //    case:
    current_index = used;
}

/*************************************************/
/* NONMEMBER FUNCTIONS for the set class         */
/*************************************************/
    
// +
//
// postcondition: the set returned is the union of
//       s1 and s2.
//
template <typename Item>
set<Item> operator +(const set<Item>& s1, const set<Item>& s2)
{
    set<Item> answer(s1.size() + s2.size());

    answer += s1; 
    answer += s2;
    return answer;
}