#ifndef MATRIX_H
#define MATRIX_H

#include <cassert>

template <class T>
class matrix
{
public:
       matrix( int i, int j );
       matrix( const matrix &other);
       ~matrix();
    matrix& operator=( const matrix &other);

    int rows() const { return x; }
    int cols() const { return y; }

    T& at( int i, int j);
    T  at( int i, int j) const;
    T& operator()( int i, int j);
    T  operator()( int i, int j) const;

    matrix& operator+=( const matrix &other);
private:
    int  x;
    int  y;
    T   *v;

    void copy( const matrix &other);
    void check( int i, int j) const;
};

template <class T>
matrix<T> operator+( const matrix<T> &x, const matrix<T> &y);

template <class T>
matrix<T>::matrix( int i, int j)
{
    x = i;
    y = j;
    v = new T[x*y];
}
template <class T>
matrix<T>::matrix( const matrix &other)
{
    copy( other);
}
template <class T>
matrix<T>::~matrix()
{
    delete [] v;
}
template <class T>
matrix<T>& matrix<T>::operator=( const matrix &other)
{
    if ( this != &other )
    {
        delete [] v;
        copy( other);
    }
    return *this;
}
template <class T>
void matrix<T>::copy( const matrix &other)
{
    x = other.x;
    y = other.y;
    v = new T[x*y];
    for ( int i = 0; i < x*y; ++i )
        v[i] = other.v[i];
}
template <class T>
void matrix<T>::check( int i, int j) const
{
    assert( 0 <= i  && i < x );
    assert( 0 <= j  && j < y );
}
template <class T>
T& matrix<T>::at( int i, int j)
{
    check(i,j);
    return operator()(i,j);
}
template <class T>
T matrix<T>::at( int i, int j) const
{
    check(i,j);
    return operator()(i,j);
}
template <class T>
T& matrix<T>::operator()( int i, int j)
{
    return v[i*y + j];
}
template <class T>
T matrix<T>::operator() ( int i, int j) const
{
    return v[i*y + j];
}
template <class T>
matrix<T>& matrix<T>::operator+=( const matrix &other)
{
    for ( int i = 0; i < x*y; ++i )
        v[i] += other.v[i];
    return *this;
}
template <class T>
matrix<T> operator+( const matrix<T> &x, const matrix<T> &y)
{
    matrix<T> result( x );
    result += y;
    return result;
}

#endif /* MATRIX_H */