#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);
    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>::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> matrix<T>::operator+( const matrix &other)
{
    matrix<T> temp( *this );
    temp += other;
    return temp;
}

#endif /* MATRIX_H */