// compile with
// g++-4.8 -o main_gcc -O3 -std=c++11 -Wall -Wextra -pedantic -Werror main.cpp square.cpp
// clang++ -o main_clang -O3 -std=c++11 -Wall -Wextra -pedantic -Werror main.cpp square.cpp

#include <algorithm>
#include <ctime>
#include <functional>
#include <iostream>
#include <iterator>
#include <numeric>
#include <string>
#include <vector>

using namespace std;

typedef vector<int> Vec;
//int n = 8;
int n = 1000000;
size_t max_print = 10;
int shift = 3;
int runs = 400;

void shift_rev( Vec& v, size_t a )
{
	reverse( v.begin(), v.end() );
	reverse( v.begin(), v.begin() + a );
	reverse( v.begin() + a, v.end() );
}

void shift_swap(Vec& v, size_t a)
{
	size_t max_s = v.size() / a;
	for( size_t s = 1; s < max_s; ++s )
		for( size_t i = 0; i < a; ++i )
			swap( v[i], v[s*a+i] );
	for( size_t i = 0; i < a; ++i )
		swap( v[i], v[(max_s*a+i) % v.size()] );
}

void print(const Vec& v)
{
	copy( v.begin(), v.end(), ostream_iterator<int>( cout, ",") );
	cout << endl;
}

void test( Vec v, function<void(Vec&, size_t)> f, const string& name )
{
	unsigned int startTime = clock();

	for ( int i = 0; i < runs; ++i )
		f( v, shift % v.size() );

	// sum the result to prevent the optimizer from removing everything.
	auto check = accumulate( v.begin(), v.end(), 0 );

	if ( v.size() <= max_print )
		print( v );

    double duration = static_cast<double>(clock() - startTime) / CLOCKS_PER_SEC;

	cout << name << " (check: " << check << "), duration: " << duration << endl;
}

int main()
{
	vector<int> v;
	v.reserve( n );

	for (int i = 1; i <= n; ++i )
		v.push_back(i);

	if ( v.size() <= max_print )
		print( v );

	test( v, &shift_rev, "rev " );
	test( v, &shift_swap, "swap" );
}