/* * Copyright (c) 2013-2020, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * * See full license text in LICENSE file at top of project tree */ #ifndef QUEUE_H__ #define QUEUE_H__ #include <queue> #include <vector> #include <mutex> #include <thread> #include <condition_variable> #include <functional> #include <utility> namespace i2p { namespace util { template<typename Element> class Queue { public: void Put(Element e) { std::unique_lock <std::mutex> l(m_QueueMutex); m_Queue.push(std::move(e)); m_NonEmpty.notify_one(); } template<template<typename, typename...> class Container, typename... R> void Put(const Container<Element, R...> &vec) { if (!vec.empty()) { std::unique_lock <std::mutex> l(m_QueueMutex); for (const auto &it: vec) m_Queue.push(std::move(it)); m_NonEmpty.notify_one(); } } Element GetNext() { std::unique_lock <std::mutex> l(m_QueueMutex); auto el = GetNonThreadSafe(); if (!el) { m_NonEmpty.wait(l); el = GetNonThreadSafe(); } return el; } Element GetNextWithTimeout(int usec) { std::unique_lock <std::mutex> l(m_QueueMutex); auto el = GetNonThreadSafe(); if (!el) { m_NonEmpty.wait_for(l, std::chrono::milliseconds(usec)); el = GetNonThreadSafe(); } return el; } void Wait() { std::unique_lock <std::mutex> l(m_QueueMutex); m_NonEmpty.wait(l); } bool Wait(int sec, int usec) { std::unique_lock <std::mutex> l(m_QueueMutex); return m_NonEmpty.wait_for(l, std::chrono::seconds(sec) + std::chrono::milliseconds(usec)) != std::cv_status::timeout; } bool IsEmpty() { std::unique_lock <std::mutex> l(m_QueueMutex); return m_Queue.empty(); } int GetSize() { std::unique_lock <std::mutex> l(m_QueueMutex); return m_Queue.size(); } void WakeUp() { m_NonEmpty.notify_all(); }; Element Get() { std::unique_lock <std::mutex> l(m_QueueMutex); return GetNonThreadSafe(); } Element Peek() { std::unique_lock <std::mutex> l(m_QueueMutex); return GetNonThreadSafe(true); } private: Element GetNonThreadSafe(bool peek = false) { if (!m_Queue.empty()) { auto el = m_Queue.front(); if (!peek) m_Queue.pop(); return el; } return nullptr; } private: std::queue <Element> m_Queue; std::mutex m_QueueMutex; std::condition_variable m_NonEmpty; }; } } #endif