Refactor intrusive_stack implementation and tests

This commit is contained in:
mutouyun 2024-06-02 18:23:56 +08:00
parent a401d3f874
commit 6ad911550e
2 changed files with 33 additions and 16 deletions

View File

@ -12,13 +12,21 @@
LIBCONCUR_NAMESPACE_BEG_ LIBCONCUR_NAMESPACE_BEG_
/// \brief Intrusive stack node.
/// \tparam T The type of the value.
template <typename T> template <typename T>
struct intrusive_node {
T value;
std::atomic<intrusive_node *> next;
};
/// \brief Intrusive stack.
/// \tparam T The type of the value.
/// \tparam Node The type of the node.
template <typename T, typename Node = intrusive_node<T>>
class intrusive_stack { class intrusive_stack {
public: public:
struct node { using node = Node;
T value;
std::atomic<node *> next{nullptr};
};
private: private:
std::atomic<node *> top_{nullptr}; std::atomic<node *> top_{nullptr};
@ -50,8 +58,8 @@ public:
return nullptr; return nullptr;
} }
} while (!top_.compare_exchange_weak(old_top, old_top->next.load(std::memory_order_relaxed) } while (!top_.compare_exchange_weak(old_top, old_top->next.load(std::memory_order_relaxed)
, std::memory_order_release , std::memory_order_release
, std::memory_order_acquire)); , std::memory_order_acquire));
return old_top; return old_top;
} }
}; };

View File

@ -10,7 +10,7 @@ TEST(intrusive_stack, construct) {
} }
TEST(intrusive_stack, construct_node) { TEST(intrusive_stack, construct_node) {
concur::intrusive_stack<int>::node n; concur::intrusive_stack<int>::node n{};
EXPECT_TRUE(n.next.load(std::memory_order_relaxed) == nullptr); EXPECT_TRUE(n.next.load(std::memory_order_relaxed) == nullptr);
} }
@ -26,18 +26,19 @@ TEST(intrusive_stack, moveable) {
TEST(intrusive_stack, push_one) { TEST(intrusive_stack, push_one) {
concur::intrusive_stack<int> s; concur::intrusive_stack<int> s;
concur::intrusive_stack<int>::node n; concur::intrusive_stack<int>::node n{123};
s.push(&n); s.push(&n);
EXPECT_FALSE(s.empty()); EXPECT_FALSE(s.empty());
EXPECT_TRUE(s.top_.load(std::memory_order_relaxed) == &n); EXPECT_TRUE(s.top_.load(std::memory_order_relaxed) == &n);
EXPECT_TRUE(n.next.load(std::memory_order_relaxed) == nullptr); EXPECT_TRUE(n.next.load(std::memory_order_relaxed) == nullptr);
EXPECT_EQ(n.value, 123);
} }
TEST(intrusive_stack, push_many) { TEST(intrusive_stack, push_many) {
concur::intrusive_stack<int> s; concur::intrusive_stack<int> s;
concur::intrusive_stack<int>::node n1; concur::intrusive_stack<int>::node n1{111111};
concur::intrusive_stack<int>::node n2; concur::intrusive_stack<int>::node n2{222222};
concur::intrusive_stack<int>::node n3; concur::intrusive_stack<int>::node n3{333333};
s.push(&n1); s.push(&n1);
s.push(&n2); s.push(&n2);
s.push(&n3); s.push(&n3);
@ -46,16 +47,20 @@ TEST(intrusive_stack, push_many) {
EXPECT_TRUE(n3.next.load(std::memory_order_relaxed) == &n2); EXPECT_TRUE(n3.next.load(std::memory_order_relaxed) == &n2);
EXPECT_TRUE(n2.next.load(std::memory_order_relaxed) == &n1); EXPECT_TRUE(n2.next.load(std::memory_order_relaxed) == &n1);
EXPECT_TRUE(n1.next.load(std::memory_order_relaxed) == nullptr); EXPECT_TRUE(n1.next.load(std::memory_order_relaxed) == nullptr);
EXPECT_EQ(n1.value, 111111);
EXPECT_EQ(n2.value, 222222);
EXPECT_EQ(n3.value, 333333);
} }
TEST(intrusive_stack, push_same) { TEST(intrusive_stack, push_same) {
concur::intrusive_stack<int> s; concur::intrusive_stack<int> s;
concur::intrusive_stack<int>::node n; concur::intrusive_stack<int>::node n{321};
s.push(&n); s.push(&n);
s.push(&n); s.push(&n);
EXPECT_FALSE(s.empty()); EXPECT_FALSE(s.empty());
EXPECT_TRUE(s.top_.load(std::memory_order_relaxed) == &n); EXPECT_TRUE(s.top_.load(std::memory_order_relaxed) == &n);
EXPECT_TRUE(n.next.load(std::memory_order_relaxed) == &n); EXPECT_TRUE(n.next.load(std::memory_order_relaxed) == &n);
EXPECT_EQ(n.value, 321);
} }
TEST(intrusive_stack, pop_empty) { TEST(intrusive_stack, pop_empty) {
@ -65,19 +70,20 @@ TEST(intrusive_stack, pop_empty) {
TEST(intrusive_stack, pop_one) { TEST(intrusive_stack, pop_one) {
concur::intrusive_stack<int> s; concur::intrusive_stack<int> s;
concur::intrusive_stack<int>::node n; concur::intrusive_stack<int>::node n{112233};
s.push(&n); s.push(&n);
EXPECT_TRUE(s.pop() == &n); EXPECT_TRUE(s.pop() == &n);
EXPECT_TRUE(s.empty()); EXPECT_TRUE(s.empty());
EXPECT_TRUE(s.top_.load(std::memory_order_relaxed) == nullptr); EXPECT_TRUE(s.top_.load(std::memory_order_relaxed) == nullptr);
EXPECT_TRUE(n.next.load(std::memory_order_relaxed) == nullptr); EXPECT_TRUE(n.next.load(std::memory_order_relaxed) == nullptr);
EXPECT_EQ(n.value, 112233);
} }
TEST(intrusive_stack, pop_many) { TEST(intrusive_stack, pop_many) {
concur::intrusive_stack<int> s; concur::intrusive_stack<int> s;
concur::intrusive_stack<int>::node n1; concur::intrusive_stack<int>::node n1{111111};
concur::intrusive_stack<int>::node n2; concur::intrusive_stack<int>::node n2{222222};
concur::intrusive_stack<int>::node n3; concur::intrusive_stack<int>::node n3{333333};
s.push(&n1); s.push(&n1);
s.push(&n2); s.push(&n2);
s.push(&n3); s.push(&n3);
@ -89,4 +95,7 @@ TEST(intrusive_stack, pop_many) {
EXPECT_TRUE(n3.next.load(std::memory_order_relaxed) == &n2); EXPECT_TRUE(n3.next.load(std::memory_order_relaxed) == &n2);
EXPECT_TRUE(n2.next.load(std::memory_order_relaxed) == &n1); EXPECT_TRUE(n2.next.load(std::memory_order_relaxed) == &n1);
EXPECT_TRUE(n1.next.load(std::memory_order_relaxed) == nullptr); EXPECT_TRUE(n1.next.load(std::memory_order_relaxed) == nullptr);
EXPECT_EQ(n1.value, 111111);
EXPECT_EQ(n2.value, 222222);
EXPECT_EQ(n3.value, 333333);
} }