Replace std::list with own doubly-linked-list
TODO iterator
This commit is contained in:
parent
3dc12683e8
commit
10899ffaab
2 changed files with 214 additions and 447 deletions
|
@ -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
|
||||||
|
|
|
@ -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());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue