// demonstrates a bug that appears as early as GCC-4.7 to current (GCC-5.1).
// affects C++11 and C++14, but not C++98 (assuming 98's inability to elide
// the copy has the same effect as generate_strings_v2).

#include <functional>
#include <algorithm>
#include <iostream>
#include <vector>
#include <cassert>

// or using deque/list makes no difference.
using stringset = std::vector<std::string>;

// @bug strings do not share data on first reassignment of result.
stringset generate_strings_v1(int count, int length)
{
	stringset set(count);
	for (auto& x : set) {
		x.resize(length);
		std::fill(x.begin(), x.end(), 'a');
	}
	return set;
}

// works as expected.
stringset generate_strings_v2(int count, int length)
{
	stringset set(count);
	for (auto& x : set) {
		x.resize(length);
		std::fill(x.begin(), x.end(), 'a');
	}
	return stringset(set);
}

// works as expected.
stringset generate_strings_v3(int count, int length)
{
	stringset set;
	for (int i = 0; i < count; i++) {
		std::string x;
		x.resize(length);
		std::fill(x.begin(), x.end(), 'a');
		set.push_back(x);
	}
	return set;
}

// works as expected.
stringset generate_strings_v4(int count, int length)
{
	stringset set(count);
	for (auto& x : set)
		x.resize(length, 'a');
	return set;
}

void test(const char* header, std::function<stringset(int, int)> genstrings,
	int count, int length)
{
	auto data_ptr_eq = [](const std::string& a, const std::string& b)
	{
		return a.data() == b.data();
	};
	
	stringset a = genstrings(count, length);
	stringset b = a;
	
	if (std::equal(a.begin(), a.end(), b.begin(), data_ptr_eq))
		std::cout << header << " : data pointer match\n";
	else {
		std::cout << header << " : data pointer mismatch\n";
		assert(a == b); // not expected; just in case.
	}
}

int main(int argc, char* argv[])
{
	int count = 1, length = 1;
	assert(length > 0 && count > 0);

	// v1
	// @bug string data is not shared on first reassignment.
	test("v1", generate_strings_v1, count, length);
	
	// v2, v3, v4 work as expected.
	test("v2", generate_strings_v2, count, length);
	test("v3", generate_strings_v3, count, length);
	test("v4", generate_strings_v4, count, length);
	return 0;
}