#include <iostream>
#include <stdexcept>
#include <vector>
#include <memory>
#include <chrono>
#include <thread>
#include <mutex>
#include <queue>
#include <condition_variable>
#include <atomic>
#include <utility>
#include <cassert>
using namespace std;
using namespace std::chrono;


#define CONCURRENT

#define N_GRAPHICS		(1 * 1000 * 1000)
#define N_THREADS		8



struct Graphic;

static vector<size_t> indexes;
static vector<unique_ptr<Graphic>> graphics;

static queue<pair<Graphic*, size_t>> q;
static mutex m;
static atomic<size_t> n_elements;


struct Graphic
{
	Graphic()
		: status(false)
	{
	}


	bool parse()
	{
		// waste time
		try
		{
			throw runtime_error("");
		} 
		catch (runtime_error)
		{
		}

		status = true;
		//return false;
		return true;
	}


	bool status;
};




static void producer()
{
	for (size_t i = 0; i < N_GRAPHICS; i++)
	{
		auto g = new Graphic();

#ifdef CONCURRENT
		graphics.emplace_back(g);
		q.emplace(make_pair(g, i));
#else
		if (g->parse())
			graphics.emplace_back(g);
		else
			delete g;
#endif
	}

	n_elements = graphics.size();
}



static void consumer()
{
	pair<Graphic*, size_t> item;

	while (true)
	{
		{
			std::unique_lock<std::mutex> lk(m);

			if (n_elements == 0)
				return;

			n_elements--;
			item = q.front();
			q.pop();
		}

		if (!item.first->parse())
		{
			assert(graphics[item.second].get() == item.first);
			delete item.first;
			graphics[item.second] = nullptr;
		}
	}
}




int main()
{
	auto start = system_clock::now();

	producer();

#ifdef CONCURRENT

	vector<thread> threads;

	for (auto i = 0; i < N_THREADS; i++)
		threads.emplace_back(consumer);

#endif

	for (size_t i = 0; i < graphics.size(); i++)
		indexes.push_back(i);

#ifdef CONCURRENT

	for (auto& t : threads)
		t.join();

#endif
	
	auto duration = duration_cast<milliseconds>(system_clock::now() - start);
	cout << "Elapsed: " << duration.count() << endl;

	for (size_t i = 0; i < graphics.size(); i++)
	{
		if (!graphics[i]->status)
		{
			cerr << "Assertion failed! (" << i << ")" << endl;
			break;
		}
	}

	cin.get();
	return 0;
}