Replace std::list with own doubly-linked-list

TODO iterator
This commit is contained in:
Stephen Seo 2019-10-29 20:33:16 +09:00
parent 3dc12683e8
commit 10899ffaab
2 changed files with 214 additions and 447 deletions

View file

@ -6,12 +6,11 @@
#include <thread> #include <thread>
#include <chrono> #include <chrono>
#include <optional> #include <optional>
#include <cassert>
#include <list> #include <list>
#include <type_traits> #include <type_traits>
// definition
template <typename T> template <typename T>
class TSLQueue { class TSLQueue {
public: public:
@ -25,7 +24,7 @@ class TSLQueue {
TSLQueue(TSLQueue &&other); TSLQueue(TSLQueue &&other);
TSLQueue &operator=(TSLQueue &&other); TSLQueue &operator=(TSLQueue &&other);
bool push(const T &data); void push(const T &data);
bool push_nb(const T &data); bool push_nb(const T &data);
std::optional<T> top(); std::optional<T> top();
std::optional<T> top_nb(); std::optional<T> top_nb();
@ -35,64 +34,41 @@ class TSLQueue {
void clear(); void clear();
bool empty(); bool empty();
unsigned long long size();
template <bool isConst, bool isRev>
class TSLQIterWrapper {
public:
TSLQIterWrapper(
std::conditional_t<isConst, const std::list<T>, std::list<T>> *container,
std::weak_ptr<void> iterValid,
std::shared_ptr<char> iterWrapperCount
);
bool isValid() const;
bool next();
bool prev();
std::optional<T> current();
/// can only be used when isRev is false
bool remove();
TSLQIterWrapper<isConst, isRev>& operator++();
TSLQIterWrapper<isConst, isRev>& operator--();
bool set(T &&newValue);
private: private:
std::conditional_t<isConst, const std::list<T>, std::list<T>> struct TSLQNode {
*containerPtr; TSLQNode() = default;
std::conditional_t<isRev, // disable copy
std::conditional_t<isConst, TSLQNode(TSLQNode& other) = delete;
typename std::list<T>::const_reverse_iterator, TSLQNode& operator=(TSLQNode& other) = delete;
typename std::list<T>::reverse_iterator>, // enable move
std::conditional_t<isConst, TSLQNode(TSLQNode&& other) = default;
typename std::list<T>::const_iterator, TSLQNode& operator=(TSLQNode&& other) = default;
typename std::list<T>::iterator>>
iter;
std::weak_ptr<void> iterValid; std::shared_ptr<TSLQNode> next;
std::shared_ptr<char> iterWrapperCount; std::weak_ptr<TSLQNode> prev;
std::unique_ptr<T> data;
}; };
TSLQIterWrapper<false, false> iter();
TSLQIterWrapper<false, true> riter();
TSLQIterWrapper<true, false> citer();
TSLQIterWrapper<true, true> criter();
private:
std::shared_ptr<char> iterValid; std::shared_ptr<char> iterValid;
std::shared_ptr<char> iterWrapperCount; std::shared_ptr<char> iterWrapperCount;
std::mutex mutex; std::mutex mutex;
std::list<T> container; std::shared_ptr<TSLQNode> head;
std::shared_ptr<TSLQNode> tail;
unsigned long long msize;
}; };
// implementation
template <typename T> template <typename T>
TSLQueue<T>::TSLQueue() : TSLQueue<T>::TSLQueue() :
iterValid(std::make_shared<char>()), iterValid(std::make_shared<char>()),
iterWrapperCount(std::make_shared<char>()) iterWrapperCount(std::make_shared<char>()),
head(std::make_shared<TSLQNode>()),
tail(std::make_shared<TSLQNode>()),
msize(0)
{ {
head->next = tail;
tail->prev = head;
} }
template <typename T> template <typename T>
@ -105,23 +81,38 @@ TSLQueue<T>::TSLQueue(TSLQueue &&other) :
iterWrapperCount(std::make_shared<char>()) iterWrapperCount(std::make_shared<char>())
{ {
std::lock_guard lock(other.mutex); std::lock_guard lock(other.mutex);
container = std::move(other.container); head = std::move(other.head);
tail = std::move(other.tail);
msize = std::move(other.msize);
} }
template <typename T> template <typename T>
TSLQueue<T> & TSLQueue<T>::operator=(TSLQueue &&other) { TSLQueue<T> & TSLQueue<T>::operator=(TSLQueue &&other) {
iterValid = std::make_shared<char>();
iterWrapperCount = std::make_shared<char>();
std::scoped_lock lock(mutex, other.mutex); std::scoped_lock lock(mutex, other.mutex);
container = std::move(other.container); head = std::move(other.head);
tail = std::move(other.tail);
msize = std::move(other.msize);
} }
template <typename T> template <typename T>
bool TSLQueue<T>::push(const T &data) { void TSLQueue<T>::push(const T &data) {
while(iterWrapperCount.use_count() > 1) { while(iterWrapperCount.use_count() > 1) {
std::this_thread::sleep_for(std::chrono::milliseconds(10)); std::this_thread::sleep_for(std::chrono::milliseconds(10));
} }
std::lock_guard lock(mutex); std::lock_guard lock(mutex);
container.push_back(data); auto newNode = std::make_shared<TSLQNode>();
return true; newNode->data = std::make_unique<T>(data);
auto last = tail->prev.lock();
assert(last);
newNode->prev = last;
newNode->next = tail;
last->next = newNode;
tail->prev = newNode;
++msize;
} }
template <typename T> template <typename T>
@ -129,7 +120,18 @@ bool TSLQueue<T>::push_nb(const T &data) {
if(iterWrapperCount.use_count() > 1) { if(iterWrapperCount.use_count() > 1) {
return false; return false;
} else if(mutex.try_lock()) { } else if(mutex.try_lock()) {
container.push_back(data); auto newNode = std::make_shared<TSLQNode>();
newNode->data = std::make_unique<T>(data);
auto last = tail->prev.lock();
assert(last);
newNode->prev = last;
newNode->next = tail;
last->next = newNode;
tail->prev = newNode;
++msize;
mutex.unlock(); mutex.unlock();
return true; return true;
} else { } else {
@ -143,10 +145,11 @@ std::optional<T> TSLQueue<T>::top() {
std::this_thread::sleep_for(std::chrono::milliseconds(10)); std::this_thread::sleep_for(std::chrono::milliseconds(10));
} }
std::lock_guard lock(mutex); std::lock_guard lock(mutex);
if(container.empty()) { if(head->next != tail) {
return std::nullopt; assert(head->next->data);
return *head->next->data.get();
} else { } else {
return container.front(); return std::nullopt;
} }
} }
@ -155,7 +158,11 @@ std::optional<T> TSLQueue<T>::top_nb() {
if(iterWrapperCount.use_count() > 1) { if(iterWrapperCount.use_count() > 1) {
return std::nullopt; return std::nullopt;
} else if(mutex.try_lock()) { } else if(mutex.try_lock()) {
std::optional<T> ret = container.front(); std::optional<T> ret = std::nullopt;
if(head->next != tail) {
assert(head->next->data);
ret = *head->next->data.get();
}
mutex.unlock(); mutex.unlock();
return ret; return ret;
} else { } else {
@ -169,10 +176,15 @@ bool TSLQueue<T>::pop() {
std::this_thread::sleep_for(std::chrono::milliseconds(10)); std::this_thread::sleep_for(std::chrono::milliseconds(10));
} }
std::lock_guard lock(mutex); std::lock_guard lock(mutex);
if(container.empty()) { if(head->next == tail) {
return false; return false;
} else { } else {
container.pop_front(); auto& newNext = head->next->next;
newNext->prev = head;
head->next = newNext;
assert(msize > 0);
--msize;
iterValid = std::make_shared<char>(); iterValid = std::make_shared<char>();
iterWrapperCount = std::make_shared<char>(); iterWrapperCount = std::make_shared<char>();
return true; return true;
@ -186,9 +198,16 @@ std::optional<T> TSLQueue<T>::top_and_pop() {
std::this_thread::sleep_for(std::chrono::milliseconds(10)); std::this_thread::sleep_for(std::chrono::milliseconds(10));
} }
std::lock_guard lock(mutex); std::lock_guard lock(mutex);
if(!container.empty()) { if(head->next != tail) {
ret = container.front(); assert(head->next->data);
container.pop_front(); ret = *head->next->data.get();
auto& newNext = head->next->next;
newNext->prev = head;
head->next = newNext;
assert(msize > 0);
--msize;
iterValid = std::make_shared<char>(); iterValid = std::make_shared<char>();
iterWrapperCount = std::make_shared<char>(); iterWrapperCount = std::make_shared<char>();
} }
@ -202,17 +221,24 @@ std::optional<T> TSLQueue<T>::top_and_pop_and_empty(bool *isEmpty) {
std::this_thread::sleep_for(std::chrono::milliseconds(10)); std::this_thread::sleep_for(std::chrono::milliseconds(10));
} }
std::lock_guard lock(mutex); std::lock_guard lock(mutex);
if(container.empty()) { if(head->next == tail) {
if(isEmpty) { if(isEmpty) {
*isEmpty = true; *isEmpty = true;
} }
} else { } else {
ret = container.front(); assert(head->next->data);
container.pop_front(); ret = *head->next->data.get();
auto& newNext = head->next->next;
newNext->prev = head;
head->next = newNext;
assert(msize > 0);
--msize;
iterValid = std::make_shared<char>(); iterValid = std::make_shared<char>();
iterWrapperCount = std::make_shared<char>(); iterWrapperCount = std::make_shared<char>();
if(isEmpty) { if(isEmpty) {
*isEmpty = container.empty(); *isEmpty = head->next == tail;
} }
} }
return ret; return ret;
@ -224,7 +250,11 @@ void TSLQueue<T>::clear() {
std::this_thread::sleep_for(std::chrono::milliseconds(10)); std::this_thread::sleep_for(std::chrono::milliseconds(10));
} }
std::lock_guard lock(mutex); std::lock_guard lock(mutex);
container.clear();
head->next = tail;
tail->prev = head;
msize = 0;
iterValid = std::make_shared<char>(); iterValid = std::make_shared<char>();
iterWrapperCount = std::make_shared<char>(); iterWrapperCount = std::make_shared<char>();
} }
@ -235,180 +265,16 @@ bool TSLQueue<T>::empty() {
std::this_thread::sleep_for(std::chrono::milliseconds(10)); std::this_thread::sleep_for(std::chrono::milliseconds(10));
} }
std::lock_guard lock(mutex); std::lock_guard lock(mutex);
return container.empty(); return head->next == tail;
} }
template <typename T> template <typename T>
template <bool isConst, bool isRev> unsigned long long TSLQueue<T>::size() {
TSLQueue<T>::TSLQIterWrapper<isConst, isRev>::TSLQIterWrapper( while(iterWrapperCount.use_count() > 1) {
std::conditional_t<isConst, const std::list<T>, std::list<T>> *container, std::this_thread::sleep_for(std::chrono::milliseconds(10));
std::weak_ptr<void> iterValid,
std::shared_ptr<char> 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 <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;
if(containerPtr->rend() == iter) {
return false;
}
}
} else {
if(containerPtr->end() == iter) {
iterValid.reset();
return false;
} else {
++iter;
if(containerPtr->end() == iter) {
return false;
}
}
}
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;
}
template <typename T>
template <bool isConst, bool isRev>
bool TSLQueue<T>::TSLQIterWrapper<isConst, isRev>::remove() {
if(!isValid()) {
return false;
} else if constexpr(isRev) {
return false;
} else {
if(containerPtr->end() == iter) {
return false;
}
}
iter = containerPtr->erase(iter);
return true;
}
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;
}
template <typename T>
template <bool isConst, bool isRev>
bool TSLQueue<T>::TSLQIterWrapper<isConst, isRev>::set(T &&newValue) {
if constexpr(isConst) {
return false;
} else {
if(!isValid()) {
return false;
}
*iter = std::forward<T>(newValue);
return true;
}
}
template <typename T>
typename TSLQueue<T>::template TSLQIterWrapper<false, false> TSLQueue<T>::iter() {
std::lock_guard lock(mutex); std::lock_guard lock(mutex);
return TSLQIterWrapper<false, false>(&container, iterValid, iterWrapperCount); return msize;
}
template <typename T>
typename TSLQueue<T>::template TSLQIterWrapper<false, true> TSLQueue<T>::riter() {
std::lock_guard lock(mutex);
return TSLQIterWrapper<false, true>(&container, iterValid, iterWrapperCount);
}
template <typename T>
typename TSLQueue<T>::template TSLQIterWrapper<true, false> TSLQueue<T>::citer() {
std::lock_guard lock(mutex);
return TSLQIterWrapper<true, false>(&container, iterValid, iterWrapperCount);
}
template <typename T>
typename TSLQueue<T>::template TSLQIterWrapper<true, true> TSLQueue<T>::criter() {
std::lock_guard lock(mutex);
return TSLQIterWrapper<true, true>(&container, iterValid, iterWrapperCount);
} }
#endif #endif

View file

@ -1,217 +1,118 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <iostream> #include <future>
#include <functional>
#include "TSLQueue.hpp" #include "TSLQueue.hpp"
TEST(TSLQueue, Usage) { TEST(TSLQueue, PushTopPopSize) {
TSLQueue<int> q; TSLQueue<int> q;
bool isEmpty;
std::optional<int> opt;
// init EXPECT_FALSE(q.top().has_value());
for(int i = 0; i < 10; ++i) {
EXPECT_EQ(i, q.size());
q.push(i);
}
for(int i = 0; i < 10; ++i) {
auto v = q.top();
ASSERT_TRUE(v.has_value());
EXPECT_EQ(v.value(), i);
EXPECT_EQ(10 - i, q.size());
EXPECT_TRUE(q.pop());
}
EXPECT_EQ(q.size(), 0);
EXPECT_FALSE(q.pop()); EXPECT_FALSE(q.pop());
}
opt = q.top_and_pop();
EXPECT_FALSE(opt.has_value()); TEST(TSLQueue, PushNB_TopNB_TopAndPop_Size) {
TSLQueue<int> q;
opt = q.top_and_pop_and_empty(&isEmpty);
EXPECT_FALSE(opt.has_value()); for(int i = 0; i < 10; ++i) {
EXPECT_TRUE(isEmpty); EXPECT_EQ(q.size(), i);
EXPECT_TRUE(q.push_nb(i));
EXPECT_TRUE(q.empty()); }
// push 1, 2, 3 for(int i = 0; i < 10; ++i) {
q.push(1); auto v = q.top_nb();
EXPECT_FALSE(q.empty()); ASSERT_TRUE(v.has_value());
opt = q.top(); EXPECT_EQ(v.value(), i);
ASSERT_TRUE(opt.has_value()); EXPECT_EQ(q.size(), 10 - i);
EXPECT_EQ(opt.value(), 1); v = q.top_and_pop();
ASSERT_TRUE(v.has_value());
q.push_nb(2); EXPECT_EQ(v.value(), i);
EXPECT_FALSE(q.empty()); }
opt = q.top_nb();
ASSERT_TRUE(opt.has_value()); {
EXPECT_EQ(opt.value(), 1); auto v = q.top_nb();
ASSERT_FALSE(v.has_value());
q.push(3); }
EXPECT_FALSE(q.empty()); {
opt = q.top(); auto v = q.top_and_pop();
ASSERT_TRUE(opt.has_value()); ASSERT_FALSE(v.has_value());
EXPECT_EQ(opt.value(), 1); }
EXPECT_EQ(q.size(), 0);
// iterators }
{
auto citer = q.citer(); TEST(TSLQueue, Push_TopAndPopAndEmpty_Size) {
opt = citer.current(); TSLQueue<int> q;
ASSERT_TRUE(opt.has_value());
EXPECT_EQ(opt.value(), 1); for(int i = 0; i < 10; ++i) {
EXPECT_FALSE(citer.set(111)); EXPECT_EQ(q.size(), i);
q.push(i);
EXPECT_TRUE(citer.next()); }
opt = citer.current();
ASSERT_TRUE(opt.has_value()); bool isEmpty;
EXPECT_EQ(opt.value(), 2); for(int i = 0; i < 10; ++i) {
EXPECT_EQ(q.size(), 10 - i);
EXPECT_TRUE(citer.next()); auto v = q.top_and_pop_and_empty(&isEmpty);
opt = citer.current(); ASSERT_TRUE(v.has_value());
ASSERT_TRUE(opt.has_value()); EXPECT_EQ(v.value(), i);
EXPECT_EQ(opt.value(), 3); EXPECT_EQ(i == 9, isEmpty);
}
EXPECT_FALSE(citer.next()); EXPECT_EQ(q.size(), 0);
opt = citer.current(); }
EXPECT_FALSE(opt.has_value());
TEST(TSLQueue, PushClearEmptySize) {
EXPECT_TRUE(citer.isValid()); TSLQueue<int> q;
EXPECT_FALSE(citer.next());
EXPECT_FALSE(citer.isValid()); for(int i = 0; i < 10; ++i) {
} EXPECT_EQ(q.size(), i);
{ q.push(i);
auto criter = q.criter(); }
opt = criter.current(); EXPECT_EQ(q.size(), 10);
ASSERT_TRUE(opt.has_value());
EXPECT_EQ(opt.value(), 3); EXPECT_FALSE(q.empty());
EXPECT_FALSE(criter.set(333)); q.clear();
EXPECT_TRUE(q.empty());
EXPECT_TRUE(criter.next()); EXPECT_EQ(q.size(), 0);
opt = criter.current(); }
ASSERT_TRUE(opt.has_value());
EXPECT_EQ(opt.value(), 2); TEST(TSLQueue, Concurrent) {
TSLQueue<int> q;
EXPECT_TRUE(criter.next());
opt = criter.current(); const auto add_fn = [] (TSLQueue<int> *q, int i) -> void {
ASSERT_TRUE(opt.has_value()); q->push(i);
EXPECT_EQ(opt.value(), 1); };
EXPECT_FALSE(criter.next()); std::future<void> futures[100];
opt = criter.current(); for(int i = 0; i < 100; ++i) {
EXPECT_FALSE(opt.has_value()); futures[i] = std::async(std::launch::async, add_fn, &q, i);
} }
{ for(int i = 0; i < 100; ++i) {
// values changed to 10, 20, 30 futures[i].wait();
auto iter = q.iter(); }
opt = iter.current();
ASSERT_TRUE(opt.has_value()); EXPECT_FALSE(q.empty());
EXPECT_EQ(opt.value(), 1); for(int i = 0; i < 100; ++i) {
EXPECT_TRUE(iter.set(10)); EXPECT_EQ(q.size(), 100 - i);
opt = iter.current(); auto v = q.top_and_pop();
ASSERT_TRUE(opt.has_value()); ASSERT_TRUE(v.has_value());
EXPECT_EQ(opt.value(), 10); EXPECT_GE(v.value(), 0);
EXPECT_LE(v.value(), 100);
EXPECT_TRUE(iter.next()); EXPECT_EQ(i == 99, q.empty());
opt = iter.current(); }
ASSERT_TRUE(opt.has_value()); EXPECT_EQ(q.size(), 0);
EXPECT_EQ(opt.value(), 2);
EXPECT_TRUE(iter.set(20));
opt = iter.current();
ASSERT_TRUE(opt.has_value());
EXPECT_EQ(opt.value(), 20);
EXPECT_TRUE(iter.next());
opt = iter.current();
ASSERT_TRUE(opt.has_value());
EXPECT_EQ(opt.value(), 3);
EXPECT_TRUE(iter.set(30));
opt = iter.current();
ASSERT_TRUE(opt.has_value());
EXPECT_EQ(opt.value(), 30);
EXPECT_FALSE(iter.next());
opt = iter.current();
EXPECT_FALSE(opt.has_value());
}
{
// values changed to 1, 2, 3
auto riter = q.riter();
opt = riter.current();
ASSERT_TRUE(opt.has_value());
EXPECT_EQ(opt.value(), 30);
EXPECT_TRUE(riter.set(3));
opt = riter.current();
ASSERT_TRUE(opt.has_value());
EXPECT_EQ(opt.value(), 3);
EXPECT_TRUE(riter.next());
opt = riter.current();
ASSERT_TRUE(opt.has_value());
EXPECT_EQ(opt.value(), 20);
EXPECT_TRUE(riter.set(2));
opt = riter.current();
ASSERT_TRUE(opt.has_value());
EXPECT_EQ(opt.value(), 2);
EXPECT_TRUE(riter.next());
opt = riter.current();
ASSERT_TRUE(opt.has_value());
EXPECT_EQ(opt.value(), 10);
EXPECT_TRUE(riter.set(1));
opt = riter.current();
ASSERT_TRUE(opt.has_value());
EXPECT_EQ(opt.value(), 1);
}
{
// remove center (2), result: 1, 3
auto iter = q.iter();
opt = iter.current();
ASSERT_TRUE(opt.has_value());
EXPECT_EQ(opt.value(), 1);
EXPECT_TRUE(iter.next());
opt = iter.current();
ASSERT_TRUE(opt.has_value());
EXPECT_EQ(opt.value(), 2);
EXPECT_TRUE(iter.remove());
opt = iter.current();
ASSERT_TRUE(opt.has_value());
EXPECT_EQ(opt.value(), 3);
EXPECT_FALSE(iter.next());
opt = iter.current();
ASSERT_FALSE(opt.has_value());
EXPECT_FALSE(iter.remove());
}
{
// remove first (1), result: 3
auto iter = q.iter();
opt = iter.current();
ASSERT_TRUE(opt.has_value());
EXPECT_EQ(opt.value(), 1);
EXPECT_TRUE(iter.remove());
opt = iter.current();
ASSERT_TRUE(opt.has_value());
EXPECT_EQ(opt.value(), 3);
EXPECT_FALSE(iter.next());
opt = iter.current();
ASSERT_FALSE(opt.has_value());
EXPECT_FALSE(iter.remove());
}
{
// remove (3), result: empty
auto iter = q.iter();
opt = iter.current();
ASSERT_TRUE(opt.has_value());
EXPECT_EQ(opt.value(), 3);
EXPECT_TRUE(iter.remove());
opt = iter.current();
EXPECT_FALSE(opt.has_value());
EXPECT_FALSE(iter.remove());
}
{
auto iter = q.iter();
opt = iter.current();
EXPECT_FALSE(opt.has_value());
}
{
auto riter = q.riter();
opt = riter.current();
EXPECT_FALSE(opt.has_value());
}
} }