#ifndef UDPC_THREADSAFE_LINKEDLIST_QUEUE_HPP #define UDPC_THREADSAFE_LINKEDLIST_QUEUE_HPP #include #include #include #include #include #include #include #include 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); // in place of std::optional which is only available in C++17 struct Entry { Entry(); Entry(const T& value); Entry(T&& rvalue); // enable copy Entry(const Entry& other) = default; Entry &operator =(const Entry& other) = default; // enable move Entry(Entry&& other) = default; Entry &operator =(Entry&& other) = default; enum Type { NONE, SOME } type; T value; bool has_value() const; operator bool () const; T& operator *(); const T& operator *() const; }; void push(const T &data); bool push_nb(const T &data); Entry top(); Entry top_nb(); bool pop(); Entry top_and_pop(); Entry top_and_pop_and_empty(bool *isEmpty); Entry top_and_pop_and_rsize(unsigned long *rsize); void clear(); bool empty(); unsigned long size(); private: struct TSLQNode { TSLQNode(); // disable copy TSLQNode(TSLQNode& other) = delete; TSLQNode& operator=(TSLQNode& other) = delete; // enable move TSLQNode(TSLQNode&& other) = default; TSLQNode& operator=(TSLQNode&& other) = default; std::shared_ptr next; std::weak_ptr prev; std::unique_ptr data; enum TSLQN_Type { TSLQN_NORMAL, TSLQN_HEAD, TSLQN_TAIL }; TSLQN_Type type; bool isNormal() const; }; class TSLQIter { public: TSLQIter(std::mutex *mutex, std::weak_ptr currentNode, unsigned long *msize); ~TSLQIter(); Entry current(); bool next(); bool prev(); bool remove(); private: std::mutex *mutex; std::weak_ptr currentNode; unsigned long *const msize; }; public: TSLQIter begin(); private: std::mutex mutex; std::shared_ptr head; std::shared_ptr tail; unsigned long msize; }; template TSLQueue::TSLQueue() : head(std::make_shared()), tail(std::make_shared()), msize(0) { head->next = tail; tail->prev = head; head->type = TSLQNode::TSLQN_Type::TSLQN_HEAD; tail->type = TSLQNode::TSLQN_Type::TSLQN_TAIL; } template TSLQueue::~TSLQueue() { } template TSLQueue::TSLQueue(TSLQueue &&other) { std::lock_guard lock(other.mutex); head = std::move(other.head); tail = std::move(other.tail); msize = std::move(other.msize); } template TSLQueue & TSLQueue::operator=(TSLQueue &&other) { std::lock_guard lock(mutex); std::lock_guard otherLock(other.mutex); head = std::move(other.head); tail = std::move(other.tail); msize = std::move(other.msize); } template TSLQueue::Entry::Entry() : type(Type::NONE), value() {} template TSLQueue::Entry::Entry(const T& value) : type(Type::SOME), value(value) {} template TSLQueue::Entry::Entry(T&& value) : type(Type::SOME), value(std::forward(value)) {} template bool TSLQueue::Entry::has_value() const { return type == Type::SOME; } template TSLQueue::Entry::operator bool() const { return has_value(); } template T& TSLQueue::Entry::operator *() { return value; } template const T& TSLQueue::Entry::operator *() const { return value; } template void TSLQueue::push(const T &data) { std::lock_guard lock(mutex); auto newNode = std::make_shared(); newNode->data = std::make_unique(data); auto last = tail->prev.lock(); assert(last); newNode->prev = last; newNode->next = tail; last->next = newNode; tail->prev = newNode; ++msize; } template bool TSLQueue::push_nb(const T &data) { if(mutex.try_lock()) { auto newNode = std::make_shared(); newNode->data = std::make_unique(data); auto last = tail->prev.lock(); assert(last); newNode->prev = last; newNode->next = tail; last->next = newNode; tail->prev = newNode; ++msize; mutex.unlock(); return true; } else { return false; } } template typename TSLQueue::Entry TSLQueue::top() { std::lock_guard lock(mutex); if(head->next != tail) { assert(head->next->data); return Entry(*head->next->data.get()); } else { return Entry(); } } template typename TSLQueue::Entry TSLQueue::top_nb() { if(mutex.try_lock()) { Entry ret; if(head->next != tail) { assert(head->next->data); ret = Entry(*head->next->data.get()); } mutex.unlock(); return ret; } else { return Entry(); } } template bool TSLQueue::pop() { std::lock_guard lock(mutex); if(head->next == tail) { return false; } else { auto& newNext = head->next->next; newNext->prev = head; head->next = newNext; assert(msize > 0); --msize; return true; } } template typename TSLQueue::Entry TSLQueue::top_and_pop() { Entry ret; std::lock_guard lock(mutex); if(head->next != tail) { assert(head->next->data); ret = Entry(*head->next->data.get()); auto& newNext = head->next->next; newNext->prev = head; head->next = newNext; assert(msize > 0); --msize; } return ret; } template typename TSLQueue::Entry TSLQueue::top_and_pop_and_empty(bool *isEmpty) { Entry ret; std::lock_guard lock(mutex); if(head->next == tail) { if(isEmpty) { *isEmpty = true; } } else { assert(head->next->data); ret = Entry(*head->next->data.get()); auto& newNext = head->next->next; newNext->prev = head; head->next = newNext; assert(msize > 0); --msize; if(isEmpty) { *isEmpty = head->next == tail; } } return ret; } template typename TSLQueue::Entry TSLQueue::top_and_pop_and_rsize(unsigned long *rsize) { Entry ret; std::lock_guard lock(mutex); if(head->next == tail) { if(rsize) { *rsize = 0; } } else { assert(head->next->data); ret = Entry(*head->next->data.get()); auto& newNext = head->next->next; newNext->prev = head; head->next = newNext; assert(msize > 0); --msize; if(rsize) { *rsize = msize; } } return ret; } template void TSLQueue::clear() { std::lock_guard lock(mutex); head->next = tail; tail->prev = head; msize = 0; } template bool TSLQueue::empty() { std::lock_guard lock(mutex); return head->next == tail; } template unsigned long TSLQueue::size() { std::lock_guard lock(mutex); return msize; } template TSLQueue::TSLQNode::TSLQNode() : type(TSLQN_Type::TSLQN_NORMAL) {} template bool TSLQueue::TSLQNode::isNormal() const { return type == TSLQN_Type::TSLQN_NORMAL; } template TSLQueue::TSLQIter::TSLQIter(std::mutex *mutex, std::weak_ptr currentNode, unsigned long *msize) : mutex(mutex), currentNode(currentNode), msize(msize) { mutex->lock(); } template TSLQueue::TSLQIter::~TSLQIter() { mutex->unlock(); } template typename TSLQueue::Entry TSLQueue::TSLQIter::current() { std::shared_ptr currentNode = this->currentNode.lock(); assert(currentNode); if(currentNode->isNormal()) { return Entry(*currentNode->data.get()); } else { return Entry(); } } template bool TSLQueue::TSLQIter::next() { std::shared_ptr currentNode = this->currentNode.lock(); assert(currentNode); if(currentNode->type == TSLQNode::TSLQN_Type::TSLQN_TAIL) { return false; } this->currentNode = currentNode->next; return currentNode->next->type != TSLQNode::TSLQN_Type::TSLQN_TAIL; } template bool TSLQueue::TSLQIter::prev() { std::shared_ptr currentNode = this->currentNode.lock(); assert(currentNode); if(currentNode->type == TSLQNode::TSLQN_Type::TSLQN_HEAD) { return false; } auto parent = currentNode->prev.lock(); assert(parent); this->currentNode = currentNode->prev; return parent->type != TSLQNode::TSLQN_Type::TSLQN_HEAD; } template bool TSLQueue::TSLQIter::remove() { std::shared_ptr currentNode = this->currentNode.lock(); assert(currentNode); if(!currentNode->isNormal()) { return false; } this->currentNode = currentNode->next; auto parent = currentNode->prev.lock(); assert(parent); currentNode->next->prev = parent; parent->next = currentNode->next; assert(*msize > 0); --(*msize); return parent->next->isNormal(); } template typename TSLQueue::TSLQIter TSLQueue::begin() { return TSLQIter(&mutex, head->next, &msize); } #endif