#include <algorithm>
#include <iomanip>
#include <iostream>
#include <string>
#include <vector>

int count_copy_construction;
int count_move_construction;
int count_copy_assignment;
int count_move_assignment;
int count_swap;
int count_comparison;

struct A {
	std::string value;
	A() : value("") {}
	A(const A &a) : value(a.value) {
		++count_copy_construction;
	}
	A(A &&a) : value(std::move(a.value)) {
		++count_move_construction;
	}
	A &operator=(const A &a) {
		++count_copy_assignment;
		value = a.value;
		return *this;
	}
	A &operator=(A &&a) {
		++count_move_assignment;
		value = std::move(a.value);
		return *this;
	}
	bool operator<(const A &a) const {
		++count_comparison;
		return value < a.value;
	}
};
void swap(A &a, A &b) {
	++count_swap;
	std::swap(a.value, b.value);
}

template<typename I>
void MergeSort(I first, I last) {
	if (last - first > 1) {
		I mid = first + (last - first) / 2;
		MergeSort(first, mid);
		MergeSort(mid, last);
		std::inplace_merge(first, mid, last);
	}
}

int main() {
	for (int method = 0; method < 1; ++method) {
		std::vector<A> a(1000000);
		unsigned first = 0;
		unsigned last = a.size();
		for (unsigned i = 0; i < 100; ++i) {
			const std::string s = std::string()
					+ (char)('a' + i / 25)
					+ (char)('a' + i % 25);
			for (unsigned j = 0; j < i + 2; ++j) {
				a[first++].value = s;
			}
			a[--last].value = s;
		}
		for (unsigned pos = first; pos < last; ++pos) {
			a[pos].value = std::string() + "z"
					+ (char)('a' + pos % 11)
					+ (char)('a' + pos % 13)
					+ (char)('a' + pos % 17)
					+ (char)('a' + pos % 19)
					+ (char)('a' + pos % 23);
		}
		count_copy_construction = 0;
		count_move_construction = 0;
		count_copy_assignment = 0;
		count_move_assignment = 0;
		count_swap = 0;
		count_comparison = 0;
		switch (method) {
			case 0:
				std::sort(a.begin(), a.end());
				break;
			case 1:
				std::partial_sort(a.begin(), a.end(), a.end());
				break;
			case 2:
				std::stable_sort(a.begin(), a.end());
				break;
			case 3:
				MergeSort(a.begin(), a.end());
				break;
		}
		std::cerr
			<< std::setw(8) << count_copy_construction << " "
			<< std::setw(8) << count_move_construction << " "
			<< std::setw(8) << count_copy_assignment << " "
			<< std::setw(8) << count_move_assignment << " "
			<< std::setw(8) << count_swap << "  "
			<< std::setw(8) << count_comparison << std::endl;
	}
	return 0;
}
