#include <iomanip>
#include <cassert>

////////////////////////////////////////////////////////////////////////
//// This header contains simple implementation of class vector     ////
////////////////////////////////////////////////////////////////////////
class Vector{
  int N;     // size of the vector
  double *m; // pointer to data
public:
  ///// constructors & destructor
  Vector(int N, double 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
  double operator[](int i) const;  // array access operator for reading
  double& 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
Vector::Vector() : N(0), m(NULL)
{};

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

// Copy constructor needed for return by value
Vector::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
Vector::~Vector()
{ delete[] m;}

// checks the bound when reading -- very usefull feature
inline double Vector::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
inline double& Vector::operator[](int i)
{
  assert(i<N && i>=0);// Writting out of bounds
  return m[i];
}

// resizing of vector
void Vector::resize(int N_)
{
  if (N_> N){ // need to deallocate
    N = N_;
    delete[] m;           // memory released
    m = new double[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).
}

void Vector::random()// fills with random numbers
{
  for (int i=0; i<N; i++) m[i] = 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
std::ostream& operator<<(std::ostream& stream, const Vector& 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!
}

