]> git.seodisparate.com - UDPConnection/commitdiff
Replace std::list with own doubly-linked-list
authorStephen Seo <seo.disparate@gmail.com>
Tue, 29 Oct 2019 11:33:16 +0000 (20:33 +0900)
committerStephen Seo <seo.disparate@gmail.com>
Tue, 29 Oct 2019 11:33:16 +0000 (20:33 +0900)
TODO iterator

cpp_impl/src/TSLQueue.hpp
cpp_impl/src/test/TestTSLQueue.cpp

index 7d03f0c38358c5cb8ff871a4c66a50a859cdcc6d..eaa73c2cae4afd600f1193b15d2563f62cb15ec5 100644 (file)
@@ -6,12 +6,11 @@
 #include <thread>
 #include <chrono>
 #include <optional>
+#include <cassert>
 
 #include <list>
 #include <type_traits>
 
-// definition
-
 template <typename T>
 class TSLQueue {
   public:
@@ -25,7 +24,7 @@ class TSLQueue {
     TSLQueue(TSLQueue &&other);
     TSLQueue &operator=(TSLQueue &&other);
 
-    bool push(const T &data);
+    void push(const T &data);
     bool push_nb(const T &data);
     std::optional<T> top();
     std::optional<T> top_nb();
@@ -35,64 +34,41 @@ class TSLQueue {
     void clear();
 
     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:
-        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;
-        std::shared_ptr<char> iterWrapperCount;
+  private:
+    struct TSLQNode {
+        TSLQNode() = default;
+        // 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<TSLQNode> next;
+        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> iterWrapperCount;
     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>
 TSLQueue<T>::TSLQueue() :
     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>
@@ -105,23 +81,38 @@ TSLQueue<T>::TSLQueue(TSLQueue &&other) :
     iterWrapperCount(std::make_shared<char>())
 {
     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>
 TSLQueue<T> & TSLQueue<T>::operator=(TSLQueue &&other) {
+    iterValid = std::make_shared<char>();
+    iterWrapperCount = std::make_shared<char>();
     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>
-bool TSLQueue<T>::push(const T &data) {
+void 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;
+    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;
 }
 
 template <typename T>
@@ -129,7 +120,18 @@ bool TSLQueue<T>::push_nb(const T &data) {
     if(iterWrapperCount.use_count() > 1) {
         return false;
     } 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();
         return true;
     } else {
@@ -143,10 +145,11 @@ std::optional<T> TSLQueue<T>::top() {
         std::this_thread::sleep_for(std::chrono::milliseconds(10));
     }
     std::lock_guard lock(mutex);
-    if(container.empty()) {
-        return std::nullopt;
+    if(head->next != tail) {
+        assert(head->next->data);
+        return *head->next->data.get();
     } else {
-        return container.front();
+        return std::nullopt;
     }
 }
 
@@ -155,7 +158,11 @@ 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();
+        std::optional<T> ret = std::nullopt;
+        if(head->next != tail) {
+            assert(head->next->data);
+            ret = *head->next->data.get();
+        }
         mutex.unlock();
         return ret;
     } else {
@@ -169,10 +176,15 @@ bool TSLQueue<T>::pop() {
         std::this_thread::sleep_for(std::chrono::milliseconds(10));
     }
     std::lock_guard lock(mutex);
-    if(container.empty()) {
+    if(head->next == tail) {
         return false;
     } else {
-        container.pop_front();
+        auto& newNext = head->next->next;
+        newNext->prev = head;
+        head->next = newNext;
+        assert(msize > 0);
+        --msize;
+
         iterValid = std::make_shared<char>();
         iterWrapperCount = std::make_shared<char>();
         return true;
@@ -186,9 +198,16 @@ std::optional<T> TSLQueue<T>::top_and_pop() {
         std::this_thread::sleep_for(std::chrono::milliseconds(10));
     }
     std::lock_guard lock(mutex);
-    if(!container.empty()) {
-        ret = container.front();
-        container.pop_front();
+    if(head->next != tail) {
+        assert(head->next->data);
+        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>();
         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::lock_guard lock(mutex);
-    if(container.empty()) {
+    if(head->next == tail) {
         if(isEmpty) {
             *isEmpty = true;
         }
     } else {
-        ret = container.front();
-        container.pop_front();
+        assert(head->next->data);
+        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>();
         iterWrapperCount = std::make_shared<char>();
         if(isEmpty) {
-            *isEmpty = container.empty();
+            *isEmpty = head->next == tail;
         }
     }
     return ret;
@@ -224,7 +250,11 @@ void TSLQueue<T>::clear() {
         std::this_thread::sleep_for(std::chrono::milliseconds(10));
     }
     std::lock_guard lock(mutex);
-    container.clear();
+
+    head->next = tail;
+    tail->prev = head;
+    msize = 0;
+
     iterValid = 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::lock_guard lock(mutex);
-    return container.empty();
-}
-
-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,
-        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;
+    return head->next == tail;
 }
 
 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;
+unsigned long long TSLQueue<T>::size() {
+    while(iterWrapperCount.use_count() > 1) {
+        std::this_thread::sleep_for(std::chrono::milliseconds(10));
     }
-}
-
-template <typename T>
-typename TSLQueue<T>::template TSLQIterWrapper<false, false> TSLQueue<T>::iter() {
-    std::lock_guard lock(mutex);
-    return TSLQIterWrapper<false, false>(&container, iterValid, iterWrapperCount);
-}
-
-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);
+    return msize;
 }
 
 #endif
index d5b97bc1438b5ecc77bce345e5b573846c7bb17f..cd961047f4e718ea7021747eb0721f54525ae8d2 100644 (file)
 #include <gtest/gtest.h>
 
-#include <iostream>
+#include <future>
+#include <functional>
 
 #include "TSLQueue.hpp"
 
-TEST(TSLQueue, Usage) {
+TEST(TSLQueue, PushTopPopSize) {
     TSLQueue<int> q;
-    bool isEmpty;
-    std::optional<int> opt;
-
-    // init
-    EXPECT_FALSE(q.pop());
 
-    opt = q.top_and_pop();
-    EXPECT_FALSE(opt.has_value());
+    EXPECT_FALSE(q.top().has_value());
 
-    opt = q.top_and_pop_and_empty(&isEmpty);
-    EXPECT_FALSE(opt.has_value());
-    EXPECT_TRUE(isEmpty);
-
-    EXPECT_TRUE(q.empty());
+    for(int i = 0; i < 10; ++i) {
+        EXPECT_EQ(i, q.size());
+        q.push(i);
+    }
 
-    // push 1, 2, 3
-    q.push(1);
-    EXPECT_FALSE(q.empty());
-    opt = q.top();
-    ASSERT_TRUE(opt.has_value());
-    EXPECT_EQ(opt.value(), 1);
+    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);
 
-    q.push_nb(2);
-    EXPECT_FALSE(q.empty());
-    opt = q.top_nb();
-    ASSERT_TRUE(opt.has_value());
-    EXPECT_EQ(opt.value(), 1);
+    EXPECT_FALSE(q.pop());
+}
 
-    q.push(3);
-    EXPECT_FALSE(q.empty());
-    opt = q.top();
-    ASSERT_TRUE(opt.has_value());
-    EXPECT_EQ(opt.value(), 1);
+TEST(TSLQueue, PushNB_TopNB_TopAndPop_Size) {
+    TSLQueue<int> q;
 
-    // iterators
-    {
-        auto citer = q.citer();
-        opt = citer.current();
-        ASSERT_TRUE(opt.has_value());
-        EXPECT_EQ(opt.value(), 1);
-        EXPECT_FALSE(citer.set(111));
-
-        EXPECT_TRUE(citer.next());
-        opt = citer.current();
-        ASSERT_TRUE(opt.has_value());
-        EXPECT_EQ(opt.value(), 2);
-
-        EXPECT_TRUE(citer.next());
-        opt = citer.current();
-        ASSERT_TRUE(opt.has_value());
-        EXPECT_EQ(opt.value(), 3);
-
-        EXPECT_FALSE(citer.next());
-        opt = citer.current();
-        EXPECT_FALSE(opt.has_value());
-
-        EXPECT_TRUE(citer.isValid());
-        EXPECT_FALSE(citer.next());
-        EXPECT_FALSE(citer.isValid());
+    for(int i = 0; i < 10; ++i) {
+        EXPECT_EQ(q.size(), i);
+        EXPECT_TRUE(q.push_nb(i));
     }
-    {
-        auto criter = q.criter();
-        opt = criter.current();
-        ASSERT_TRUE(opt.has_value());
-        EXPECT_EQ(opt.value(), 3);
-        EXPECT_FALSE(criter.set(333));
-
-        EXPECT_TRUE(criter.next());
-        opt = criter.current();
-        ASSERT_TRUE(opt.has_value());
-        EXPECT_EQ(opt.value(), 2);
-
-        EXPECT_TRUE(criter.next());
-        opt = criter.current();
-        ASSERT_TRUE(opt.has_value());
-        EXPECT_EQ(opt.value(), 1);
-
-        EXPECT_FALSE(criter.next());
-        opt = criter.current();
-        EXPECT_FALSE(opt.has_value());
+
+    for(int i = 0; i < 10; ++i) {
+        auto v = q.top_nb();
+        ASSERT_TRUE(v.has_value());
+        EXPECT_EQ(v.value(), i);
+        EXPECT_EQ(q.size(), 10 - i);
+        v = q.top_and_pop();
+        ASSERT_TRUE(v.has_value());
+        EXPECT_EQ(v.value(), i);
     }
+
     {
-        // values changed to 10, 20, 30
-        auto iter = q.iter();
-        opt = iter.current();
-        ASSERT_TRUE(opt.has_value());
-        EXPECT_EQ(opt.value(), 1);
-        EXPECT_TRUE(iter.set(10));
-        opt = iter.current();
-        ASSERT_TRUE(opt.has_value());
-        EXPECT_EQ(opt.value(), 10);
-
-        EXPECT_TRUE(iter.next());
-        opt = iter.current();
-        ASSERT_TRUE(opt.has_value());
-        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());
+        auto v = q.top_nb();
+        ASSERT_FALSE(v.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);
+        auto v = q.top_and_pop();
+        ASSERT_FALSE(v.has_value());
     }
+    EXPECT_EQ(q.size(), 0);
+}
 
-    {
-        // 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());
+TEST(TSLQueue, Push_TopAndPopAndEmpty_Size) {
+    TSLQueue<int> q;
+
+    for(int i = 0; i < 10; ++i) {
+        EXPECT_EQ(q.size(), i);
+        q.push(i);
     }
 
-    {
-        // 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());
+    bool isEmpty;
+    for(int i = 0; i < 10; ++i) {
+        EXPECT_EQ(q.size(), 10 - i);
+        auto v = q.top_and_pop_and_empty(&isEmpty);
+        ASSERT_TRUE(v.has_value());
+        EXPECT_EQ(v.value(), i);
+        EXPECT_EQ(i == 9, isEmpty);
     }
+    EXPECT_EQ(q.size(), 0);
+}
 
-    {
-        // 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());
+TEST(TSLQueue, PushClearEmptySize) {
+    TSLQueue<int> q;
+
+    for(int i = 0; i < 10; ++i) {
+        EXPECT_EQ(q.size(), i);
+        q.push(i);
     }
+    EXPECT_EQ(q.size(), 10);
 
-    {
-        auto iter = q.iter();
-        opt = iter.current();
-        EXPECT_FALSE(opt.has_value());
+    EXPECT_FALSE(q.empty());
+    q.clear();
+    EXPECT_TRUE(q.empty());
+    EXPECT_EQ(q.size(), 0);
+}
+
+TEST(TSLQueue, Concurrent) {
+    TSLQueue<int> q;
+
+    const auto add_fn = [] (TSLQueue<int> *q, int i) -> void {
+        q->push(i);
+    };
+
+    std::future<void> futures[100];
+    for(int i = 0; i < 100; ++i) {
+        futures[i] = std::async(std::launch::async, add_fn, &q, i);
     }
-    {
-        auto riter = q.riter();
-        opt = riter.current();
-        EXPECT_FALSE(opt.has_value());
+    for(int i = 0; i < 100; ++i) {
+        futures[i].wait();
+    }
+
+    EXPECT_FALSE(q.empty());
+    for(int i = 0; i < 100; ++i) {
+        EXPECT_EQ(q.size(), 100 - i);
+        auto v = q.top_and_pop();
+        ASSERT_TRUE(v.has_value());
+        EXPECT_GE(v.value(), 0);
+        EXPECT_LE(v.value(), 100);
+        EXPECT_EQ(i == 99, q.empty());
     }
+    EXPECT_EQ(q.size(), 0);
 }