#include <iomanip>
#include <cassert>
#include <complex>

////////////////////////////////////////////////////////////////////////
//// This header contains simple implementation of class vector     ////
////////////////////////////////////////////////////////////////////////
template <class T>
class Vector{
  int N;     // size of the vector
  T *m; // pointer to data
public:
  ///// constructors & destructor
  Vector(int N, const T& def_val=0); // constructor takes size as an argument
  Vector();                        // default constructor is called when no arguments are given
  Vector(const Vector& A);         // copy constructor necessary for return by value
  ~Vector();                       // desctructor necessary because we have pointers to deallocate
  ///// other class members
  T operator[](int i) const;  // array access operator for reading
  T& operator[](int i);       // array access operator for writting
  int size() const {return N;}     // returns size
  void resize(int N);              // resizes existing vector
  void random();                   // fills with random numbers
};

// Default constructor creates empty vector
template <class T>
Vector<T>::Vector() : N(0), m(NULL)
{};

// Given initial size and default value, vector is initialized
template <class T>
Vector<T>::Vector(int N_, const T& def_val) : N(N_)
{
  m = new T[N];
  for (int i=0; i<N; i++) m[i] = def_val;
}

// Copy constructor needed for return by value
template <class T>
Vector<T>::Vector(const Vector& A) : N(0)
{
  resize(A.N);
  std::copy(A.m, A.m+N, m);
}

// Whenever constructor allocates memory, destructor needs to deallocate the same
// chunk of memory
template <class T>
Vector<T>::~Vector()
{ delete[] m;}

// checks the bound when reading -- very usefull feature
template <class T>
inline T Vector<T>::operator[](int i) const
{
  assert(i<N && i>=0);// Reading out of bounds
  return m[i];
}

// checks the bound when writting -- even more usefull feature
template <class T>
inline T& Vector<T>::operator[](int i)
{
  assert(i<N && i>=0);// Writting out of bounds
  return m[i];
}

// resizing of vector
template <class T>
void Vector<T>::resize(int N_)
{
  if (N_> N){ // need to deallocate
    N = N_;
    delete[] m;           // memory released
    m = new T[N];    // and larger size created
  }else{
    N = N_;               // only decrease the size, no need to allocate memory
  }
  // Note that better class would need to carry information about temporary size (N) and
  // actual size (let's say N0). The allocation/deallocation should occur only if
  // desired new size of vector is bigger than actual size N0 (not temporary size N).
}

template <class T>
void Vector<T>::random()// fills with random numbers
{
  std::cerr<<"Not specialized yet for this class!"<<std::endl;
}
template <>
void Vector<double>::random()// fills with random numbers
{
  for (int i=0; i<N; i++) m[i] = drand48();
}
template <>
void Vector<std::complex<double> >::random()// fills with random numbers
{
  for (int i=0; i<N; i++) m[i] = std::complex<double>(drand48(), drand48());
}

// Printing of a vector in Python style.
// Note that it can not be member function (vector appears on the right hand side)
// Note that it needs to return stream by reference and takes stream as first argument
// and object as second argument
template <class T>
std::ostream& operator<<(std::ostream& stream, const Vector<T>& m)
{
  stream<<"[";
  for (int i=0; i<m.size(); i++){
    stream<<std::setw(10)<<m[i];
    if (i!=m.size()-1) stream<<", ";
    else stream<<"]";
  }
  return stream; // Be careful! You have to return stream otherwise it will coredump!
}

