#ifndef __LQUEUE_H__
#define __LQUEUE_H__

/*
 * Copyright (c) 2014 Pavel Shramov <shramov@mexmat.net>
 *
 * lqueue is free software; you can redistribute it and/or modify
 * it under the terms of the MIT license. See LICENSE for details.
 */

#include <memory>
#include <atomic>

/*
 * XXX: Probably there are some races...
 */
template <typename T>
class lqueue
{
	struct node {
		node * next;
		T value;

		node() : next(0), value() {}
	};

	std::atomic<node *> _head;
	std::atomic<node *> _tail;

public:
	lqueue() : _head(new node), _tail(_head.load()) {}	
	~lqueue()
	{
		for (auto ptr = _head.load(); ptr;)
		{
			std::unique_ptr<node> p(ptr);
			ptr = ptr->next;
		}
	}

	// Passing by value to have fast push(T &&)
	void push(T value)
	{
		auto e = new node;
		do {
			auto p = _tail.load();
			if (!_tail.compare_exchange_weak(p, e))
				continue;
			std::swap(p->value, value);
			//XXX: Write barrier is needed here
			std::atomic_thread_fence(std::memory_order_release);
			p->next = e;
			return;
		} while (1);
	}

	std::pair<T, bool> pop()
	{
		do {
			auto p = _head.load();
			if (!p->next) return std::make_pair(T(), false);
			if (!_head.compare_exchange_weak(p, p->next))
				continue;
			std::unique_ptr<node> ptr(p);
			return std::make_pair(p->value, true);
		} while (1);
	}
};

#endif//__LQUEUE_H__