Project

General

Profile

Download (6.23 KB) Statistics
| Branch: | Revision:
#ifndef __PROTECTEDQUEUE_H__
#define __PROTECTEDQUEUE_H__

#include <condition_variable>
#include <functional>
#include <iostream>
#include <queue>
#include <mutex>


template<class T>
class ProtectedQueue
{
public:
ProtectedQueue()
: m_terminateFlag(false),
p_itemAddedCallback(nullptr),
p_itemRemovedCallback(nullptr)
{}
virtual ~ProtectedQueue() {}
/**
* Add a new element to the back of the queue
*/
inline void push_back(T newElement)
{
{
std::lock_guard<std::mutex> lock(m_mutex);
m_deque.push_back(newElement);
// Call item added callback if one exists
if (p_itemAddedCallback != nullptr)
{
(*p_itemAddedCallback)(m_deque.size());
}
}
m_CV.notify_one();
}

inline void push_front(T newElement)
{
{
std::lock_guard<std::mutex> lock(m_mutex);
m_deque.push_front(newElement);
// Call item added callback if one exists
if (p_itemAddedCallback != nullptr)
{
(*p_itemAddedCallback)(m_deque.size());
}
}
m_CV.notify_one();
}
/**
* Retrieve the first element of the queue and remove it from the queue
*/
inline T pop_front()
{
// Wait on queue blocking
std::unique_lock<std::mutex> muxLock(m_mutex);
while (m_deque.empty())
{
m_CV.wait_for(muxLock, std::chrono::milliseconds(100));

// If we've been asked to terminate, break out and return
// NOTE: the return value is garbage if terminate has been
// called prior this call returning
if (m_terminateFlag)
{
T elementToReturn{};
return elementToReturn;
}
}

T elementToReturn = m_deque.front();
m_deque.pop_front();
// Call item removed callback if one exists
if (p_itemRemovedCallback != nullptr)
{
(*p_itemRemovedCallback)(m_deque.size());
}
return elementToReturn;
}

/**
* Retrieve the first element of the queue and remove it from the queue
*/
inline T pop_front(bool waitOnEmptyQueue, bool& elementReturned)
{
// Wait on queue blocking
std::unique_lock<std::mutex> muxLock(m_mutex);
if (waitOnEmptyQueue)
{
while (m_deque.empty())
{
m_CV.wait_for(muxLock, std::chrono::milliseconds(100));

// If we've been asked to terminate, break out and return
// NOTE: the return value is garbage if terminate has been
// called prior this call returning
if (m_terminateFlag)
{
break;
}
}
}

T elementToReturn{};
if (m_deque.size() > 0)
{
elementReturned = true;
elementToReturn = m_deque.front();
m_deque.pop_front();
// Call item removed callback if one exists
if (p_itemRemovedCallback != nullptr)
{
(*p_itemRemovedCallback)(m_deque.size());
}
}
else
{
elementReturned = false;
}

return elementToReturn;
}
/**
* Terminate any waiting pop_front() requests
*/
void terminate()
{
m_terminateFlag = true;
m_CV.notify_all();
}

/*
* Resets the terminate flag to allow the queue to function again after
* being terminated previously
*/
void unTerminate()
{
m_terminateFlag = false;
}

void cleanup(std::function<void(T)>& callback)
{
// Call the callback on all remaining items in the queue purging
// each afterwards
{
std::lock_guard<std::mutex> lock(m_mutex);
while (! m_deque.empty())
{
callback(m_deque.front());
m_deque.pop_front();
}
}
m_CV.notify_all();
}
inline bool empty() const
{
std::lock_guard<std::mutex> lock(m_mutex);
return m_deque.empty();
}
inline uint32_t size() const
{
std::lock_guard<std::mutex> lock(m_mutex);
return m_deque.size();
}
inline void setItemAddedCallback(std::function<void(uint32_t)>& callback)
{
p_itemAddedCallback = &callback;
}
inline void setItemRemovedCallback(std::function<void(uint32_t)>& callback)
{
p_itemRemovedCallback = &callback;
}

/**
* Get the position of item in the queue
*
* @return position of item in queue if it exists, else UINT32_MAX
*/
uint32_t getPositionOf(T item) const
{
std::lock_guard<std::mutex> lock(m_mutex);
uint32_t position = 0;
for (auto queueItem : m_deque)
{
if (item == queueItem)
{
return position;
}
position ++;
}

return UINT32_MAX;
}
/**
* Removes item from queue. If item does not exist in queue, nothing
* will happen
*
* @param item Item to remove
*/
void removeItem(T item)
{
std::lock_guard<std::mutex> lock(m_mutex);

// Erase item from deque
auto iter = m_deque.begin();
while (iter != m_deque.end())
{
if (*iter == item)
{
m_deque.erase(iter);
return;
}
++iter;
}
}

uint32_t count(T item)
{
std::lock_guard<std::mutex> lock(m_mutex);

uint32_t count = 0;
for (auto queueItem : m_deque)
{
if (item == queueItem)
{
count++;
}
}

return count;
}
private:

bool m_terminateFlag;
std::deque<T> m_deque;
mutable std::mutex m_mutex;
std::condition_variable m_CV;
std::function<void(uint32_t)>* p_itemAddedCallback;
std::function<void(uint32_t)>* p_itemRemovedCallback;

};

#endif
(4-4/5)