#include <valarray>
#include <stdexcept>

#include "matrix.h"

using namespace std;

template<class T>
  matrix<T>::matrix(std::valarray<T>&& v_, std::size_t m_, std::size_t n_)
    : v(v_), m(m_), n(n_) {
      if (v.size() != m * n)
        throw invalid_argument("valarray of wrong size");
}
template<class T>
  matrix<T>::matrix(size_t m_, size_t n_, T val_)
    : v(val_, m_ * n_),m(m_),n(n_) {}

template<class T>
  size_t matrix<T>::rows() const { return m; }
template<class T>
  size_t matrix<T>::columns() const { return n; }

template<class T>
  matrix<T>::matrix_slice::matrix_slice
    (valarray<T>& v_, size_t start, size_t size, size_t stride)
    : slice(start, size, stride), v(v_) {}

template<class T>
  T& matrix<T>::matrix_slice::operator[](size_t i)
    { return v[start() + i*stride()]; }
template<class T>
  T matrix<T>::matrix_slice::operator[](size_t i) const
    { return v[start() + i*stride()]; }
template<class T>
  matrix<T>::matrix_slice::operator valarray<T>() const {
    valarray<T> v(size());
    for (size_t i = 0; i < size(); i++)
      v[i] = (*this)[i];
    return v;
  }

template<class T>
  typename matrix<T>::matrix_slice
    matrix<T>::operator[](size_t i) { return row(i); }
template<class T>
  typename matrix<T>::matrix_slice matrix<T>::row(size_t i)
    { return matrix<T>::matrix_slice{v, i*n, n, 1}; }
template<class T>
  typename matrix<T>::matrix_slice matrix<T>::column(size_t j)
    { return matrix<T>::matrix_slice{v, j, m, n}; }

template<class T>
  matrix<T>::operator valarray<T>() const {
    return v;
  }

template<class T>
  T* matrix<T>::begin()
    { return std::begin(v); }
template<class T>
  T* matrix<T>::end()
    { return std::end(v); }

template class matrix<double>;
