//  File:    Vec.h
//  Author:  Chuck Stewart, revised from the original by Koenig and Moo.
//  Purpose:  Illustrate a simple implementation of the vector class.  
//
//  Here are some details (see the associated lecture notes for a more
//  complete discussion):
//
//    . The class is templated, just like the vector class is in the
//      standard library.  This creates the need for new notation in
//      the class declaration and additional syntactic complexity in
//      the member functions.  T, the template parameter, is treated
//      like an ordinary type.  One important difference from ordinary
//      (non-templated) classes is that the there is no separate .cpp
//      file and no separate compilation.  This header file must be
//      #included wherever it is needed.
//
//    . This class uses a dynamically allocated array (of T's) as its
//      underlying implementation.  The member variable m_data is a
//      pointer to the start of the array.  The member variable m_size
//      indicates the size of the array, in the vector sense of the
//      word "size".  This is the number of currently used array
//      locations.  The third member variable, m_alloc, indicates the
//      size of the currently allocated array.  It is important that
//      the code always ensures that m_size <= m_alloc and when a
//      push_back or resize call would violate this condition, a new
//      and larger array is reallocated and the old contents are
//      copied. 
//
//    . Finally, the code here, uses new and delete for its dynamic
//      memory allocation instead of the more sophisticated allocators
//      discussed in Section 11.5 of the Koenig and Moo text.  There
//      are some technical reasons why allocators are better, but we
//      will use new and delete for now.

#ifndef Vec_h_
#define Vec_h_

template <class T> class Vec {
public:   
  //  Typedefs
  typedef T* iterator;
  typedef const T* const_iterator;
  typedef unsigned int size_type;

public:   //  Constructors, destructors and assignment operator
  Vec() { this->create(); }
  explicit Vec(size_type n, const T& t = T()) { this->create(n, t); }
  Vec(const Vec& v) { copy(v); }
  ~Vec() { delete [] m_data; }

  Vec& operator=( const Vec& v ); 

public:   //  Member functions and other operators
  T& operator[] ( size_type i ) { return m_data[i]; }
  const T& operator[] ( size_type i ) const { return m_data[i]; }

  void push_back(const T& t);
  iterator erase( iterator p );
  void resize( size_type n, const T& fill_in_value = T());
  void clear() { delete [] m_data;  create(); }

  bool empty() const { return m_size == 0; }
  size_type size() const { return m_size; }

public:   //  Iterator operations --- these are just pointer operations
  iterator begin() { return m_data; }
  const_iterator begin() const { return m_data; }
  iterator end() { return m_data + m_size; }
  const_iterator end() const { return m_data + m_size; }

private:
  T* m_data;         //  Pointer to first location in the allocated array
  size_type m_size;  //  Number of elements stored in the vector
  size_type m_alloc; //  Number of array locations allocated.  m_size <= m_alloc 

private:  
  void create();
  void create(size_type n, const T& val);
  void copy( const Vec<T>& v ); 
};


// Create an empty vector (null pointers).
template <class T> 
void Vec<T>::create()
{
  m_data = 0;            // Null pointer
  m_size = m_alloc = 0;  // No memory locations
}


//  Create a vector with size n, each location having the given value
template <class T>
void Vec<T>::create( size_type n, const T& val)
{
  m_data = new T[n];
  m_size = m_alloc = n;
  for ( T* p = m_data; p != m_data + m_size; ++p )
    *p = val;
}


//  Assign one vector to another, avoiding duplicate copying.
template <class T>
Vec<T>& Vec<T> :: operator=( const Vec<T>& v )
{
  if ( this != &v )  // avoid doing anything for self-assignment
    {
      delete [] m_data;
      this -> copy( v );
    }
  return *this;
}


//  Create the vector as a copy of the given vector.  To be written
//  during lecture.
template <class T>
void Vec<T> :: copy( const Vec<T>& old )
{
  this->m_alloc = old.m_alloc;
  this->m_size = old.m_size;
  this->m_data = new T[this->m_alloc];

  //  Copy the data
  for ( size_type i = 0; i < this->m_size; ++i )
    this -> m_data[ i ] = old.m_data[ i ];
}


//  Add a value to the back of the current vector, increasing its
//  size by 1.  Before doing this actual operator, however, check to
//  see if the size has reached the end of the allocation.  If so,
//  double the size of the allocated array, copying the old values to
//  the new array.
template <class T>
void Vec<T> :: push_back( const T& val )
{
  if ( m_alloc == m_size )
    {
      //  Do memory stuff


    }
  m_data[m_size] = val;
  ++m_size;
}


//  Copy each entry of the array above the iterator (this is just a T*
//  --- a pointer to a T) down one location.  Return the iterator,
//  which will have the same value, but point to a different location.
template <class T>
typename Vec<T> :: iterator 
Vec<T> :: erase( iterator p )
{







}


//  Change the size of the vector to n.  If n is less than or equal to
//  the current size, just change the size.  If n is greater than the
//  current size, the new slots must be filled in with the given
//  value.  Re-allocation should occur only if necessary.  push_back
//  should not be used.

template <class T>
void Vec<T> :: resize( size_type n, const T& fill_in_value )
{








}

#endif


