
#include <iostream>
#include <iomanip>
#include <windows.h>

using namespace std;

unsigned const gc_Rows = 1000, gc_Cols = 1000, gc_LoopCount = 2000;
unsigned g_Data [gc_Rows][gc_Cols];

double TimerInvFrequency ()
{
    LARGE_INTEGER q;
	QueryPerformanceFrequency (&q);
	return 1.0 / q.QuadPart;
}

double const gc_InvFreq = TimerInvFrequency ();

double ReadTime ()
{
	LARGE_INTEGER q;
	QueryPerformanceCounter (&q);
	return q.QuadPart * gc_InvFreq;
}

#define _BENCHMARK_BEGIN()						\
{												\
	double _min = 1000, _max = 0, _total = 0;	\
	for (unsigned n = 0; n < gc_LoopCount; ++n)	\
	{											\
		double t0 = ReadTime ();				\


#define _BENCHMARK_END(case_name)				\
		double dt = ReadTime() - t0;			\
												\
		_total += dt;							\
		if (dt < _min) _min = dt;				\
		if (dt > _max) _max = dt;				\
	}											\
	cout << case_name << ": "					\
		<< "min:" << fixed << setprecision(6) << _min								\
		<< ", " << "avg:" << fixed << setprecision(6) << (_total / gc_LoopCount)	\
		<< ", " << "max:" << fixed << setprecision(6) << _max						\
		<< endl;								\
}												\


int main ()
{
	// Fill the data arrays
	for (unsigned i = 0, v = 0; i < gc_Rows; ++i)
		for (unsigned j = 0; j < gc_Cols; ++j, ++v)
			g_Data[i][j] = v;

	// Simple iteration
	_BENCHMARK_BEGIN()
		volatile unsigned sum = 0;
		for (unsigned i = 0; i < gc_Rows; ++i)
			for (unsigned j = 0; j < gc_Cols; ++j)
				sum += g_Data[i][j];
	_BENCHMARK_END("Simple iteration (nested loops)")

	_BENCHMARK_BEGIN()
		volatile unsigned sum = 0;
		for (unsigned i = 0; i < gc_Rows * gc_Cols; ++i)
				sum += g_Data[i / gc_Cols][i % gc_Cols];
	_BENCHMARK_END("    Simple iteration (one loop)")

	_BENCHMARK_BEGIN()
		volatile unsigned sum = 0;
		unsigned * p = &(g_Data[0][0]);
		for (unsigned i = 0; i < gc_Rows * gc_Cols; ++i)
				sum += *p++;
	_BENCHMARK_END("   Pointer iteration (one loop)")

	_BENCHMARK_BEGIN()
		volatile unsigned sum = 0;
		for (auto & i : g_Data)
			for (auto j : i)
				sum += j;
	_BENCHMARK_END(" Range-based for (nested loops)")

	_BENCHMARK_BEGIN()
		volatile unsigned sum = 0;
		for (auto const & i : g_Data)
			for (auto const & j : i)
				sum += j;
	_BENCHMARK_END(" Range(const ref)(nested loops)")


	return 0;
}
