Commit 9cf034e4 by FritzFlorian

Unify interface from different deques

parent daee4696
Pipeline #1264 failed with stages
in 50 seconds
...@@ -23,6 +23,7 @@ add_library(pls STATIC ...@@ -23,6 +23,7 @@ add_library(pls STATIC
include/pls/internal/data_structures/aligned_stack.h src/internal/data_structures/aligned_stack.cpp include/pls/internal/data_structures/aligned_stack.h src/internal/data_structures/aligned_stack.cpp
include/pls/internal/data_structures/aligned_stack_impl.h include/pls/internal/data_structures/aligned_stack_impl.h
include/pls/internal/data_structures/locking_deque.h include/pls/internal/data_structures/locking_deque.h
include/pls/internal/data_structures/locking_deque_impl.h
include/pls/internal/data_structures/work_stealing_deque.h include/pls/internal/data_structures/work_stealing_deque_impl.h include/pls/internal/data_structures/work_stealing_deque.h include/pls/internal/data_structures/work_stealing_deque_impl.h
include/pls/internal/data_structures/stamped_integer.h include/pls/internal/data_structures/stamped_integer.h
......
...@@ -28,7 +28,8 @@ struct locking_deque_container : public locking_deque_item<Item> { ...@@ -28,7 +28,8 @@ struct locking_deque_container : public locking_deque_item<Item> {
Content content_; Content content_;
public: public:
explicit locking_deque_container(const Content &content_) : content_{content_} {} template<typename ...ARGS>
explicit locking_deque_container(ARGS &&... args) : content_{std::forward<ARGS>(args)...} {}
}; };
/** /**
...@@ -52,73 +53,20 @@ class locking_deque { ...@@ -52,73 +53,20 @@ class locking_deque {
explicit locking_deque(aligned_stack *stack) explicit locking_deque(aligned_stack *stack)
: stack_{stack}, head_{nullptr}, tail_{nullptr}, lock_{} {} : stack_{stack}, head_{nullptr}, tail_{nullptr}, lock_{} {}
template<typename T> template<typename T, typename ...ARGS>
T *push_tail(const T &new_item) { T *push_tail(ARGS &&... args);
static_assert(std::is_same<Item, T>::value || std::is_base_of<Item, T>::value, template<typename T, typename Function, typename ...ARGS>
"Must only push types of <Item> onto work_stealing_deque<Item>"); T *push_tail_cb(const Function &after_creation, ARGS &&... args);
Item *pop_tail();
std::lock_guard<base::spin_lock> lock{lock_}; Item *pop_head();
auto deque_item = stack_->push<locking_deque_container<Item, T>>(new_item);
deque_item->item_ = &deque_item->content_; void release_memory_until(state state);
state save_state();
if (tail_ != nullptr) {
tail_->next_ = deque_item;
} else {
head_ = deque_item;
}
deque_item->prev_ = tail_;
deque_item->next_ = nullptr;
tail_ = deque_item;
return &deque_item->content_;
}
Item *pop_tail() {
std::lock_guard<base::spin_lock> lock{lock_};
if (tail_ == nullptr) {
return nullptr;
}
auto result = tail_;
tail_ = tail_->prev_;
if (tail_ == nullptr) {
head_ = nullptr;
} else {
tail_->next_ = nullptr;
}
return result->item_;
}
Item *pop_head() {
std::lock_guard<base::spin_lock> lock{lock_};
if (head_ == nullptr) {
return nullptr;
}
auto result = head_;
head_ = head_->next_;
if (head_ == nullptr) {
tail_ = nullptr;
} else {
head_->prev_ = nullptr;
}
return result->item_;
}
void release_memory_until(state state) {
stack_->reset_state(state);
}
state save_state() {
return stack_->save_state();
}
}; };
} }
} }
} }
#include "locking_deque_impl.h"
#endif //PLS_LOCKING_DEQUE_H #endif //PLS_LOCKING_DEQUE_H
#ifndef PLS_LOCKING_DEQUE_IMPL_H_
#define PLS_LOCKING_DEQUE_IMPL_H_
namespace pls {
namespace internal {
namespace data_structures {
template<typename Item>
template<typename T, typename ...ARGS>
T *locking_deque<Item>::push_tail(ARGS &&... args) {
return push_tail_cb<T>([](T *) {}, std::forward<ARGS>(args)...);
}
template<typename Item>
template<typename T, typename Function, typename ...ARGS>
T *locking_deque<Item>::push_tail_cb(const Function &after_creation, ARGS &&...args) {
static_assert(std::is_same<Item, T>::value || std::is_base_of<Item, T>::value,
"Must only push types of <Item> onto work_stealing_deque<Item>");
std::lock_guard<base::spin_lock> lock{lock_};
auto deque_item = stack_->push<locking_deque_container<Item, T>>(std::forward<ARGS>(args)...);
deque_item->item_ = &deque_item->content_;
after_creation(&deque_item->content_);
if (tail_ != nullptr) {
tail_->next_ = deque_item;
} else {
head_ = deque_item;
}
deque_item->prev_ = tail_;
deque_item->next_ = nullptr;
tail_ = deque_item;
return &deque_item->content_;
}
template<typename Item>
Item *locking_deque<Item>::pop_tail() {
std::lock_guard<base::spin_lock> lock{lock_};
if (tail_ == nullptr) {
return nullptr;
}
auto result = tail_;
tail_ = tail_->prev_;
if (tail_ == nullptr) {
head_ = nullptr;
} else {
tail_->next_ = nullptr;
}
return result->item_;
}
template<typename Item>
Item *locking_deque<Item>::pop_head() {
std::lock_guard<base::spin_lock> lock{lock_};
if (head_ == nullptr) {
return nullptr;
}
auto result = head_;
head_ = head_->next_;
if (head_ == nullptr) {
tail_ = nullptr;
} else {
head_->prev_ = nullptr;
}
return result->item_;
}
template<typename Item>
void locking_deque<Item>::release_memory_until(state state) {
stack_->reset_state(state);
}
template<typename Item>
typename locking_deque<Item>::state locking_deque<Item>::save_state() {
return stack_->save_state();
}
}
}
}
#endif //PLS_LOCKING_DEQUE_IMPL_H_
...@@ -75,11 +75,6 @@ class work_stealing_deque { ...@@ -75,11 +75,6 @@ class work_stealing_deque {
previous_tail_{0} { previous_tail_{0} {
reset_base_pointer(); reset_base_pointer();
} }
work_stealing_deque(const work_stealing_deque &other) : stack_{other.stack_},
base_pointer_{other.base_pointer_},
head_{other.head_.load()},
tail_{other.tail_.load()},
previous_tail_{other.previous_tail_} {}
template<typename T, typename ...ARGS> template<typename T, typename ...ARGS>
T *push_tail(ARGS &&... args); T *push_tail(ARGS &&... args);
......
...@@ -76,145 +76,172 @@ TEST_CASE("aligned stack stores objects correctly", "[internal/data_structures/a ...@@ -76,145 +76,172 @@ TEST_CASE("aligned stack stores objects correctly", "[internal/data_structures/a
} }
} }
TEST_CASE("deque stores objects correctly", "[internal/data_structures/deque.h]") { TEST_CASE("work_stealing_deque functions correctly", "[internal/data_structures/work_stealing_deque.h]") {
class my_item {
};
constexpr long data_size = 2 << 14;
char data[data_size];
aligned_stack stack{data, data_size};
locking_deque<int> deque{&stack};
int one = 1, two = 2, three = 3;
SECTION("add and remove items form the tail") { SECTION("add and remove items form the tail") {
deque.push_tail(one); constexpr long data_size = 2 << 14;
deque.push_tail(two); char data[data_size];
deque.push_tail(three); aligned_stack stack{data, data_size};
work_stealing_deque<int> deque{&stack};
REQUIRE(*deque.pop_tail() == three);
REQUIRE(*deque.pop_tail() == two); int one = 1, two = 2, three = 3, four = 4;
REQUIRE(*deque.pop_tail() == one);
} SECTION("add and remove items form the tail") {
deque.push_tail<int>(one);
SECTION("handles getting empty by popping the tail correctly") { deque.push_tail<int>(two);
deque.push_tail(one); deque.push_tail<int>(three);
REQUIRE(*deque.pop_tail() == one);
REQUIRE(*deque.pop_tail() == three);
deque.push_tail(two); REQUIRE(*deque.pop_tail() == two);
REQUIRE(*deque.pop_tail() == two); REQUIRE(*deque.pop_tail() == one);
} }
SECTION("remove items form the head") { SECTION("handles getting empty by popping the tail correctly") {
deque.push_tail(one); deque.push_tail<int>(one);
deque.push_tail(two); REQUIRE(*deque.pop_tail() == one);
deque.push_tail(three);
deque.push_tail<int>(two);
REQUIRE(*deque.pop_head() == one); REQUIRE(*deque.pop_tail() == two);
REQUIRE(*deque.pop_head() == two); }
REQUIRE(*deque.pop_head() == three);
} SECTION("remove items form the head") {
deque.push_tail<int>(one);
SECTION("handles getting empty by popping the head correctly") { deque.push_tail<int>(two);
deque.push_tail(one); deque.push_tail<int>(three);
REQUIRE(*deque.pop_head() == one);
REQUIRE(*deque.pop_head() == one);
deque.push_tail(two); REQUIRE(*deque.pop_head() == two);
REQUIRE(*deque.pop_head() == two); REQUIRE(*deque.pop_head() == three);
} }
SECTION("handles getting empty by popping the head and tail correctly") { SECTION("handles getting empty by popping the head correctly") {
deque.push_tail(one); deque.push_tail<int>(one);
REQUIRE(*deque.pop_tail() == one); REQUIRE(*deque.pop_head() == one);
deque.push_tail(two); deque.push_tail<int>(two);
REQUIRE(*deque.pop_head() == two); REQUIRE(*deque.pop_head() == two);
}
deque.push_tail(three);
REQUIRE(*deque.pop_tail() == three); SECTION("handles getting empty by popping the head and tail correctly") {
deque.push_tail<int>(one);
REQUIRE(*deque.pop_tail() == one);
deque.push_tail<int>(two);
REQUIRE(*deque.pop_head() == two);
deque.push_tail<int>(three);
REQUIRE(*deque.pop_tail() == three);
}
SECTION("handles jumps bigger 1 correctly") {
deque.push_tail<int>(one);
deque.push_tail<int>(two);
REQUIRE(*deque.pop_tail() == two);
deque.push_tail<int>(three);
deque.push_tail<int>(four);
REQUIRE(*deque.pop_head() == one);
REQUIRE(*deque.pop_head() == three);
REQUIRE(*deque.pop_head() == four);
}
SECTION("handles stack reset 1 correctly when emptied by tail") {
deque.push_tail<int>(one);
auto state = deque.save_state();
deque.push_tail<int>(two);
REQUIRE(*deque.pop_tail() == two);
deque.release_memory_until(state);
REQUIRE(*deque.pop_tail() == one);
deque.push_tail<int>(three);
deque.push_tail<int>(four);
REQUIRE(*deque.pop_head() == three);
REQUIRE(*deque.pop_tail() == four);
}
} }
} }
TEST_CASE("work stealing deque stores objects correctly", "[internal/data_structures/aligned_stack.h]") { TEST_CASE("locking_deque functions correctly", "[internal/data_structures/locking_deque.h]") {
constexpr long data_size = 2 << 14;
char data[data_size];
aligned_stack stack{data, data_size};
work_stealing_deque<int> deque{&stack};
int one = 1, two = 2, three = 3, four = 4;
SECTION("add and remove items form the tail") { SECTION("add and remove items form the tail") {
deque.push_tail<int>(one); constexpr long data_size = 2 << 14;
deque.push_tail<int>(two); char data[data_size];
deque.push_tail<int>(three); aligned_stack stack{data, data_size};
locking_deque<int> deque{&stack};
REQUIRE(*deque.pop_tail() == three);
REQUIRE(*deque.pop_tail() == two); int one = 1, two = 2, three = 3, four = 4;
REQUIRE(*deque.pop_tail() == one);
} SECTION("add and remove items form the tail") {
deque.push_tail<int>(one);
SECTION("handles getting empty by popping the tail correctly") { deque.push_tail<int>(two);
deque.push_tail<int>(one); deque.push_tail<int>(three);
REQUIRE(*deque.pop_tail() == one);
REQUIRE(*deque.pop_tail() == three);
deque.push_tail<int>(two); REQUIRE(*deque.pop_tail() == two);
REQUIRE(*deque.pop_tail() == two); REQUIRE(*deque.pop_tail() == one);
} }
SECTION("remove items form the head") { SECTION("handles getting empty by popping the tail correctly") {
deque.push_tail<int>(one); deque.push_tail<int>(one);
deque.push_tail<int>(two); REQUIRE(*deque.pop_tail() == one);
deque.push_tail<int>(three);
deque.push_tail<int>(two);
REQUIRE(*deque.pop_head() == one); REQUIRE(*deque.pop_tail() == two);
REQUIRE(*deque.pop_head() == two); }
REQUIRE(*deque.pop_head() == three);
} SECTION("remove items form the head") {
deque.push_tail<int>(one);
SECTION("handles getting empty by popping the head correctly") { deque.push_tail<int>(two);
deque.push_tail<int>(one); deque.push_tail<int>(three);
REQUIRE(*deque.pop_head() == one);
REQUIRE(*deque.pop_head() == one);
deque.push_tail<int>(two); REQUIRE(*deque.pop_head() == two);
REQUIRE(*deque.pop_head() == two); REQUIRE(*deque.pop_head() == three);
} }
SECTION("handles getting empty by popping the head and tail correctly") { SECTION("handles getting empty by popping the head correctly") {
deque.push_tail<int>(one); deque.push_tail<int>(one);
REQUIRE(*deque.pop_tail() == one); REQUIRE(*deque.pop_head() == one);
deque.push_tail<int>(two); deque.push_tail<int>(two);
REQUIRE(*deque.pop_head() == two); REQUIRE(*deque.pop_head() == two);
}
deque.push_tail<int>(three);
REQUIRE(*deque.pop_tail() == three); SECTION("handles getting empty by popping the head and tail correctly") {
} deque.push_tail<int>(one);
REQUIRE(*deque.pop_tail() == one);
SECTION("handles jumps bigger 1 correctly") {
deque.push_tail<int>(one); deque.push_tail<int>(two);
deque.push_tail<int>(two); REQUIRE(*deque.pop_head() == two);
REQUIRE(*deque.pop_tail() == two);
deque.push_tail<int>(three);
deque.push_tail<int>(three); REQUIRE(*deque.pop_tail() == three);
deque.push_tail<int>(four); }
REQUIRE(*deque.pop_head() == one);
REQUIRE(*deque.pop_head() == three); SECTION("handles jumps bigger 1 correctly") {
REQUIRE(*deque.pop_head() == four); deque.push_tail<int>(one);
} deque.push_tail<int>(two);
REQUIRE(*deque.pop_tail() == two);
SECTION("handles stack reset 1 correctly when emptied by tail") {
deque.push_tail<int>(one); deque.push_tail<int>(three);
auto state = deque.save_state(); deque.push_tail<int>(four);
deque.push_tail<int>(two); REQUIRE(*deque.pop_head() == one);
REQUIRE(*deque.pop_tail() == two); REQUIRE(*deque.pop_head() == three);
REQUIRE(*deque.pop_head() == four);
deque.release_memory_until(state); }
REQUIRE(*deque.pop_tail() == one);
SECTION("handles stack reset 1 correctly when emptied by tail") {
deque.push_tail<int>(three); deque.push_tail<int>(one);
deque.push_tail<int>(four); auto state = deque.save_state();
REQUIRE(*deque.pop_head() == three); deque.push_tail<int>(two);
REQUIRE(*deque.pop_tail() == four); REQUIRE(*deque.pop_tail() == two);
deque.release_memory_until(state);
REQUIRE(*deque.pop_tail() == one);
deque.push_tail<int>(three);
deque.push_tail<int>(four);
REQUIRE(*deque.pop_head() == three);
REQUIRE(*deque.pop_tail() == four);
}
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment