#include <iostream>
#include <cmath>

class WrappedMatrix
{
public:
    WrappedMatrix( int size ) : m_size(size)
    {
        m_data = new int*[size];
        for ( int i = 0; i < size; ++i )
        {
            m_data[i] = new int[size];
        }
    }
    
    ~WrappedMatrix()
    {
        for ( int i = 0; i < m_size; ++i )
        {
            delete[] m_data[i];
        }
        delete[] m_data;
    }
    
    inline int size() const { return m_size; }
    
    int** raw() { return m_data; }
    
    class Iterator
    {
    public:
        Iterator( WrappedMatrix& base, int x, int y ) : m_base(base), m_x(x), m_y(y)
        {
        }
        
        int& operator*() { return m_base.raw()[m_x][m_y]; }
        
        Iterator& operator++()
        {
            if((++m_x == m_base.size() ) && (++m_y != m_base.size()))
                m_x = 0;

            return *this;   
        }
        
        bool operator==( const Iterator &rhs ) { return m_x == rhs.m_x && m_y == rhs.m_y; }
        bool operator!=( const Iterator &rhs ) { return m_x != rhs.m_x || m_y != rhs.m_y; }
        
    public:
        WrappedMatrix& m_base;
        int m_x, m_y;
    };
    
    Iterator begin() { return Iterator( *this, 0, 0 ); }
    Iterator end() { return Iterator( *this, m_size, m_size ); }
    
    
private:
    int m_size;
    int** m_data;
};

int f(int x)
{
    return x * x;
    //return static_cast<int>( std::sin( static_cast<double>(x) / 1000.0 ) * 10000.0 );
}

int main()
{
    //int size = 10000;
    int size = 5000;
    WrappedMatrix w1( size ), w2( size );
    
    // Initialise
    std::cout << "Filling array" << std::endl;
    for ( int x = 0; x < size; ++x )
    {
        for ( int y = 0; y < size; ++y )
        {
            w1.raw()[x][y] = x + y;
        }
    }
    

    std::cout << "Calculating first loop" << std::endl;
    //for ( int c = 0; c < 10; ++c )
    {
        if (1)
        {
            for ( int x = 0; x < size; ++x )
            {
                for ( int y = 0; y < size; ++y )
                {
                    w2.raw()[x][y] = f(w1.raw()[x][y]);
                }
            }
        }
        else
        {
            WrappedMatrix::Iterator it1( w1.begin() ), it2( w2.begin() );
            
            while ( it1 != w1.end() )
            {
                *it2 = f(*it1);
                //w2.raw()[it2.m_x][it2.m_y] = f(w1.raw()[it1.m_x][it1.m_y]);
                ++it1; ++it2;
            }
        }
    }
    
    
    return 0;
}
