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_
/// \brief Intrusive stack node.
/// \tparam T The type of the value.
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 {
public:
struct node {
T value;
std::atomic<node *> next{nullptr};
};
using node = Node;
private:
std::atomic<node *> top_{nullptr};
@ -50,8 +58,8 @@ public:
return nullptr;
}
} while (!top_.compare_exchange_weak(old_top, old_top->next.load(std::memory_order_relaxed)
, std::memory_order_release
, std::memory_order_acquire));
, std::memory_order_release
, std::memory_order_acquire));
return old_top;
}
};

View File

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