#include <queue>
#include <mutex>
#include <condition_variable>

template <typename T>
class ThreadQueue {
public:
	ThreadQueue() = default;
	~ThreadQueue() = default;

	void push(const T& value) {
		std::lock_guard<std::mutex> lock(mutex_);
		queue_.push(value);
		condition_.notify_one();
	}

	T pop() {
		std::unique_lock<std::mutex> lock(mutex_);
		condition_.wait(lock, [this] { return !queue_.empty(); });
		T value = queue_.front();
		queue_.pop();
		return value;
	}

	bool empty() const {
		std::lock_guard<std::mutex> lock(mutex_);
		return queue_.empty();
	}

	size_t size() const {
		std::lock_guard<std::mutex> lock(mutex_);
		return queue_.size();
	}
private:
	std::queue<T> queue_;
	mutable std::mutex mutex_;
	std::condition_variable condition_;
};
