2019-10-22 11:24:23 +00:00
|
|
|
#ifndef UDPC_THREADSAFE_LINKEDLIST_QUEUE_HPP
|
|
|
|
#define UDPC_THREADSAFE_LINKEDLIST_QUEUE_HPP
|
|
|
|
|
|
|
|
#include <memory>
|
|
|
|
#include <mutex>
|
2019-10-24 08:49:28 +00:00
|
|
|
#include <thread>
|
|
|
|
#include <chrono>
|
2019-10-22 11:24:23 +00:00
|
|
|
#include <optional>
|
|
|
|
|
|
|
|
#include <list>
|
|
|
|
#include <type_traits>
|
|
|
|
|
|
|
|
// definition
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
class TSLQueue {
|
|
|
|
public:
|
|
|
|
TSLQueue();
|
|
|
|
~TSLQueue();
|
|
|
|
|
|
|
|
// disable copy
|
|
|
|
TSLQueue(const TSLQueue &other) = delete;
|
|
|
|
TSLQueue &operator=(const TSLQueue &other) = delete;
|
|
|
|
// enable move
|
|
|
|
TSLQueue(TSLQueue &&other);
|
|
|
|
TSLQueue &operator=(TSLQueue &&other);
|
|
|
|
|
|
|
|
bool push(const T &data);
|
2019-10-24 08:49:28 +00:00
|
|
|
bool push_nb(const T &data);
|
2019-10-22 11:24:23 +00:00
|
|
|
std::optional<T> top();
|
2019-10-24 08:49:28 +00:00
|
|
|
std::optional<T> top_nb();
|
2019-10-22 11:24:23 +00:00
|
|
|
bool pop();
|
|
|
|
std::optional<T> top_and_pop();
|
|
|
|
std::optional<T> top_and_pop_and_empty(bool *isEmpty);
|
|
|
|
void clear();
|
|
|
|
|
|
|
|
bool empty();
|
|
|
|
|
|
|
|
template <bool isConst, bool isRev>
|
|
|
|
class TSLQIterWrapper {
|
|
|
|
public:
|
2019-10-24 08:49:28 +00:00
|
|
|
TSLQIterWrapper(
|
|
|
|
std::conditional_t<isConst, const std::list<T>, std::list<T>> *container,
|
|
|
|
std::weak_ptr<void> iterValid,
|
|
|
|
std::shared_ptr<void> iterWrapperCount
|
|
|
|
);
|
2019-10-22 11:24:23 +00:00
|
|
|
|
|
|
|
bool isValid() const;
|
|
|
|
|
|
|
|
bool next();
|
|
|
|
bool prev();
|
|
|
|
std::optional<T> current();
|
|
|
|
|
2019-10-24 08:58:13 +00:00
|
|
|
TSLQIterWrapper<isConst, isRev>& operator++();
|
|
|
|
TSLQIterWrapper<isConst, isRev>& operator--();
|
|
|
|
|
2019-10-22 11:24:23 +00:00
|
|
|
private:
|
|
|
|
std::conditional_t<isConst, const std::list<T>, std::list<T>>
|
|
|
|
*containerPtr;
|
|
|
|
std::conditional_t<isRev,
|
|
|
|
std::conditional_t<isConst,
|
|
|
|
typename std::list<T>::const_reverse_iterator,
|
|
|
|
typename std::list<T>::reverse_iterator>,
|
|
|
|
std::conditional_t<isConst,
|
|
|
|
typename std::list<T>::const_iterator,
|
|
|
|
typename std::list<T>::iterator>>
|
|
|
|
iter;
|
|
|
|
|
|
|
|
std::weak_ptr<void> iterValid;
|
2019-10-24 08:49:28 +00:00
|
|
|
std::shared_ptr<void> iterWrapperCount;
|
2019-10-22 11:24:23 +00:00
|
|
|
};
|
|
|
|
|
2019-10-24 08:49:28 +00:00
|
|
|
TSLQIterWrapper<false, false> iter();
|
|
|
|
TSLQIterWrapper<false, true> riter();
|
|
|
|
TSLQIterWrapper<true, false> citer();
|
|
|
|
TSLQIterWrapper<true, true> criter();
|
|
|
|
|
2019-10-22 11:24:23 +00:00
|
|
|
private:
|
|
|
|
std::shared_ptr<void> iterValid;
|
2019-10-24 08:49:28 +00:00
|
|
|
std::shared_ptr<void> iterWrapperCount;
|
|
|
|
std::mutex mutex;
|
|
|
|
std::list<T> container;
|
2019-10-22 11:24:23 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// implementation
|
|
|
|
|
|
|
|
template <typename T>
|
2019-10-24 08:49:28 +00:00
|
|
|
TSLQueue<T>::TSLQueue() :
|
|
|
|
iterValid(std::make_shared<void>()),
|
|
|
|
iterWrapperCount(std::make_shared<void>())
|
|
|
|
{
|
2019-10-22 11:24:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
TSLQueue<T>::~TSLQueue() {
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
2019-10-24 08:49:28 +00:00
|
|
|
TSLQueue<T>::TSLQueue(TSLQueue &&other) :
|
|
|
|
iterValid(std::make_shared<void>()),
|
|
|
|
iterWrapperCount(std::make_shared<void>())
|
|
|
|
{
|
|
|
|
std::lock_guard lock(other.mutex);
|
|
|
|
container = std::move(other.container);
|
2019-10-22 11:24:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
TSLQueue<T> & TSLQueue<T>::operator=(TSLQueue &&other) {
|
2019-10-24 08:49:28 +00:00
|
|
|
std::scoped_lock lock(mutex, other.mutex);
|
|
|
|
container = std::move(other.container);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
bool TSLQueue<T>::push(const T &data) {
|
|
|
|
while(iterWrapperCount.use_count() > 1) {
|
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
|
|
|
}
|
|
|
|
std::lock_guard lock(mutex);
|
|
|
|
container.push_back(data);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
bool TSLQueue<T>::push_nb(const T &data) {
|
|
|
|
if(iterWrapperCount.use_count() > 1) {
|
|
|
|
return false;
|
|
|
|
} else if(mutex.try_lock()) {
|
|
|
|
container.push_back(data);
|
|
|
|
mutex.unlock();
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
std::optional<T> TSLQueue<T>::top() {
|
|
|
|
while(iterWrapperCount.use_count() > 1) {
|
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
|
|
|
}
|
|
|
|
std::lock_guard lock(mutex);
|
|
|
|
if(container.empty()) {
|
|
|
|
return std::nullopt;
|
|
|
|
} else {
|
|
|
|
return container.front();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
std::optional<T> TSLQueue<T>::top_nb() {
|
|
|
|
if(iterWrapperCount.use_count() > 1) {
|
|
|
|
return std::nullopt;
|
|
|
|
} else if(mutex.try_lock()) {
|
|
|
|
std::optional<T> ret = container.front();
|
|
|
|
mutex.unlock();
|
|
|
|
return ret;
|
|
|
|
} else {
|
|
|
|
return std::nullopt;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
bool TSLQueue<T>::pop() {
|
|
|
|
while(iterWrapperCount.use_count() > 1) {
|
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
|
|
|
}
|
|
|
|
std::lock_guard lock(mutex);
|
|
|
|
if(container.empty()) {
|
|
|
|
return false;
|
|
|
|
} else {
|
|
|
|
container.pop_front();
|
|
|
|
iterValid = std::make_shared<void>();
|
|
|
|
iterWrapperCount = std::make_shared<void>();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
std::optional<T> TSLQueue<T>::top_and_pop() {
|
|
|
|
std::optional<T> ret = std::nullopt;
|
|
|
|
while(iterWrapperCount.use_count() > 1) {
|
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
|
|
|
}
|
|
|
|
std::lock_guard lock(mutex);
|
|
|
|
if(!container.empty()) {
|
|
|
|
ret = container.front();
|
|
|
|
container.pop_front();
|
|
|
|
iterValid = std::make_shared<void>();
|
|
|
|
iterWrapperCount = std::make_shared<void>();
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
std::optional<T> TSLQueue<T>::top_and_pop_and_empty(bool *isEmpty) {
|
|
|
|
std::optional<T> ret = std::nullopt;
|
|
|
|
while(iterWrapperCount.use_count() > 1) {
|
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
|
|
|
}
|
|
|
|
std::lock_guard lock(mutex);
|
|
|
|
if(container.empty()) {
|
|
|
|
if(isEmpty) {
|
|
|
|
*isEmpty = true;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ret = container.front();
|
|
|
|
container.pop_front();
|
|
|
|
iterValid = std::make_shared<void>();
|
|
|
|
iterWrapperCount = std::make_shared<void>();
|
|
|
|
if(isEmpty) {
|
|
|
|
*isEmpty = container.empty();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
void TSLQueue<T>::clear() {
|
|
|
|
while(iterWrapperCount.use_count() > 1) {
|
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
|
|
|
}
|
|
|
|
std::lock_guard lock(mutex);
|
|
|
|
container.clear();
|
|
|
|
iterValid = std::make_shared<void>();
|
|
|
|
iterWrapperCount = std::make_shared<void>();
|
2019-10-22 11:24:23 +00:00
|
|
|
}
|
|
|
|
|
2019-10-24 08:51:40 +00:00
|
|
|
template <typename T>
|
|
|
|
bool TSLQueue<T>::empty() {
|
|
|
|
while(iterWrapperCount.use_count() > 1) {
|
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
|
|
|
}
|
|
|
|
std::lock_guard lock(mutex);
|
|
|
|
return container.empty();
|
|
|
|
}
|
|
|
|
|
2019-10-22 11:24:23 +00:00
|
|
|
template <typename T>
|
|
|
|
template <bool isConst, bool isRev>
|
|
|
|
TSLQueue<T>::TSLQIterWrapper<isConst, isRev>::TSLQIterWrapper(
|
|
|
|
std::conditional_t<isConst, const std::list<T>, std::list<T>> *container,
|
2019-10-24 08:49:28 +00:00
|
|
|
std::weak_ptr<void> iterValid,
|
|
|
|
std::shared_ptr<void> iterWrapperCount) :
|
2019-10-22 11:24:23 +00:00
|
|
|
containerPtr(container),
|
2019-10-24 08:49:28 +00:00
|
|
|
iterValid(iterValid),
|
|
|
|
iterWrapperCount(iterWrapperCount) {
|
2019-10-22 11:24:23 +00:00
|
|
|
if constexpr (isRev) {
|
|
|
|
if constexpr (isConst) {
|
|
|
|
iter = containerPtr->crbegin();
|
|
|
|
} else {
|
|
|
|
iter = containerPtr->rbegin();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if constexpr (isConst) {
|
|
|
|
iter = containerPtr->cbegin();
|
|
|
|
} else {
|
|
|
|
iter = containerPtr->begin();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
template <bool isConst, bool isRev>
|
|
|
|
bool TSLQueue<T>::TSLQIterWrapper<isConst, isRev>::isValid() const {
|
|
|
|
return !iterValid.expired();
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
template <bool isConst, bool isRev>
|
|
|
|
bool TSLQueue<T>::TSLQIterWrapper<isConst, isRev>::next() {
|
|
|
|
if(!isValid()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if constexpr (isRev) {
|
|
|
|
if(containerPtr->rend() == iter) {
|
|
|
|
iterValid.reset();
|
|
|
|
return false;
|
|
|
|
} else {
|
|
|
|
++iter;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if(containerPtr->end() == iter) {
|
|
|
|
iterValid.reset();
|
|
|
|
return false;
|
|
|
|
} else {
|
|
|
|
++iter;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
template <bool isConst, bool isRev>
|
|
|
|
bool TSLQueue<T>::TSLQIterWrapper<isConst, isRev>::prev() {
|
|
|
|
if(!isValid()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if constexpr (isRev) {
|
|
|
|
if(containerPtr->rbegin() == iter) {
|
|
|
|
iterValid.reset();
|
|
|
|
return false;
|
|
|
|
} else {
|
|
|
|
--iter;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if(containerPtr->begin() == iter) {
|
|
|
|
iterValid.reset();
|
|
|
|
return false;
|
|
|
|
} else {
|
|
|
|
--iter;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
template <bool isConst, bool isRev>
|
|
|
|
std::optional<T> TSLQueue<T>::TSLQIterWrapper<isConst, isRev>::current() {
|
|
|
|
if(!isValid()) {
|
|
|
|
return std::nullopt;
|
|
|
|
} else {
|
|
|
|
if constexpr (isRev) {
|
|
|
|
if(containerPtr->rend() == iter) {
|
|
|
|
return std::nullopt;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if(containerPtr->end() == iter) {
|
|
|
|
return std::nullopt;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return *iter;
|
|
|
|
}
|
|
|
|
|
2019-10-24 08:58:13 +00:00
|
|
|
template <typename T>
|
|
|
|
template <bool isConst, bool isRev>
|
|
|
|
typename TSLQueue<T>::template TSLQIterWrapper<isConst, isRev>& TSLQueue<T>::TSLQIterWrapper<isConst, isRev>::operator++() {
|
|
|
|
next();
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
template <bool isConst, bool isRev>
|
|
|
|
typename TSLQueue<T>::template TSLQIterWrapper<isConst, isRev>& TSLQueue<T>::TSLQIterWrapper<isConst, isRev>::operator--() {
|
|
|
|
prev();
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2019-10-24 08:49:28 +00:00
|
|
|
template <typename T>
|
|
|
|
typename TSLQueue<T>::template TSLQIterWrapper<false, false> TSLQueue<T>::iter() {
|
|
|
|
return TSLQIterWrapper<false, false>(&container, iterValid, iterWrapperCount);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
typename TSLQueue<T>::template TSLQIterWrapper<false, true> TSLQueue<T>::riter() {
|
|
|
|
return TSLQIterWrapper<false, true>(&container, iterValid, iterWrapperCount);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
typename TSLQueue<T>::template TSLQIterWrapper<true, false> TSLQueue<T>::citer() {
|
|
|
|
return TSLQIterWrapper<true, false>(&container, iterValid, iterWrapperCount);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
typename TSLQueue<T>::template TSLQIterWrapper<true, true> TSLQueue<T>::criter() {
|
|
|
|
return TSLQIterWrapper<true, true>(&container, iterValid, iterWrapperCount);
|
|
|
|
}
|
|
|
|
|
2019-10-22 11:24:23 +00:00
|
|
|
#endif
|