#ifndef UDPC_THREADSAFE_LINKEDLIST_QUEUE_HPP #define UDPC_THREADSAFE_LINKEDLIST_QUEUE_HPP #include #include #include #include #include #include #include // definition template 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); bool push_nb(const T &data); std::optional top(); std::optional top_nb(); bool pop(); std::optional top_and_pop(); std::optional top_and_pop_and_empty(bool *isEmpty); void clear(); bool empty(); template class TSLQIterWrapper { public: TSLQIterWrapper( std::conditional_t, std::list> *container, std::weak_ptr iterValid, std::shared_ptr iterWrapperCount ); bool isValid() const; bool next(); bool prev(); std::optional current(); private: std::conditional_t, std::list> *containerPtr; std::conditional_t::const_reverse_iterator, typename std::list::reverse_iterator>, std::conditional_t::const_iterator, typename std::list::iterator>> iter; std::weak_ptr iterValid; std::shared_ptr iterWrapperCount; }; TSLQIterWrapper iter(); TSLQIterWrapper riter(); TSLQIterWrapper citer(); TSLQIterWrapper criter(); private: std::shared_ptr iterValid; std::shared_ptr iterWrapperCount; std::mutex mutex; std::list container; }; // implementation template TSLQueue::TSLQueue() : iterValid(std::make_shared()), iterWrapperCount(std::make_shared()) { } template TSLQueue::~TSLQueue() { } template TSLQueue::TSLQueue(TSLQueue &&other) : iterValid(std::make_shared()), iterWrapperCount(std::make_shared()) { std::lock_guard lock(other.mutex); container = std::move(other.container); } template TSLQueue & TSLQueue::operator=(TSLQueue &&other) { std::scoped_lock lock(mutex, other.mutex); container = std::move(other.container); } template bool TSLQueue::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 bool TSLQueue::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 std::optional TSLQueue::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 std::optional TSLQueue::top_nb() { if(iterWrapperCount.use_count() > 1) { return std::nullopt; } else if(mutex.try_lock()) { std::optional ret = container.front(); mutex.unlock(); return ret; } else { return std::nullopt; } } template bool TSLQueue::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(); iterWrapperCount = std::make_shared(); return true; } } template std::optional TSLQueue::top_and_pop() { std::optional 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(); iterWrapperCount = std::make_shared(); } return ret; } template std::optional TSLQueue::top_and_pop_and_empty(bool *isEmpty) { std::optional 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(); iterWrapperCount = std::make_shared(); if(isEmpty) { *isEmpty = container.empty(); } } return ret; } template void TSLQueue::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(); iterWrapperCount = std::make_shared(); } template template TSLQueue::TSLQIterWrapper::TSLQIterWrapper( std::conditional_t, std::list> *container, std::weak_ptr iterValid, std::shared_ptr iterWrapperCount) : containerPtr(container), iterValid(iterValid), iterWrapperCount(iterWrapperCount) { 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 template bool TSLQueue::TSLQIterWrapper::isValid() const { return !iterValid.expired(); } template template bool TSLQueue::TSLQIterWrapper::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 template bool TSLQueue::TSLQIterWrapper::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 template std::optional TSLQueue::TSLQIterWrapper::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; } template typename TSLQueue::template TSLQIterWrapper TSLQueue::iter() { return TSLQIterWrapper(&container, iterValid, iterWrapperCount); } template typename TSLQueue::template TSLQIterWrapper TSLQueue::riter() { return TSLQIterWrapper(&container, iterValid, iterWrapperCount); } template typename TSLQueue::template TSLQIterWrapper TSLQueue::citer() { return TSLQIterWrapper(&container, iterValid, iterWrapperCount); } template typename TSLQueue::template TSLQIterWrapper TSLQueue::criter() { return TSLQIterWrapper(&container, iterValid, iterWrapperCount); } #endif