TEST(AtomicIntrusiveLinkedList, Basic) { TestIntrusiveObject a(1), b(2), c(3); TestIntrusiveObject::List list; EXPECT_TRUE(list.empty()); { EXPECT_TRUE(list.insertHead(&a)); EXPECT_FALSE(list.insertHead(&b)); EXPECT_FALSE(list.empty()); size_t id = 0; list.sweep([&](TestIntrusiveObject* obj) mutable { ++id; EXPECT_EQ(id, obj->id()); }); EXPECT_TRUE(list.empty()); } // Try re-inserting the same item (b) and a new item (c) { EXPECT_TRUE(list.insertHead(&b)); EXPECT_FALSE(list.insertHead(&c)); EXPECT_FALSE(list.empty()); size_t id = 1; list.sweep([&](TestIntrusiveObject* obj) mutable { ++id; EXPECT_EQ(id, obj->id()); }); EXPECT_TRUE(list.empty()); } TestIntrusiveObject::List movedList = std::move(list); }
TEST(AtomicIntrusiveLinkedList, Stress) { constexpr size_t kNumThreads = 32; constexpr size_t kNumElements = 100000; std::vector<TestIntrusiveObject> elements; for (size_t i = 0; i < kNumThreads * kNumElements; ++i) { elements.emplace_back(i); } TestIntrusiveObject::List list; std::vector<std::thread> threads; for (size_t threadId = 0; threadId < kNumThreads; ++threadId) { threads.emplace_back( [threadId, kNumThreads, kNumElements, &list, &elements]() { for (size_t id = 0; id < kNumElements; ++id) { list.insertHead(&elements[threadId + kNumThreads * id]); } }); } std::vector<size_t> ids; TestIntrusiveObject* prev{nullptr}; while (ids.size() < kNumThreads * kNumElements) { list.sweep([&](TestIntrusiveObject* current) { ids.push_back(current->id()); if (prev && prev->id() % kNumThreads == current->id() % kNumThreads) { EXPECT_EQ(prev->id() + kNumThreads, current->id()); } prev = current; }); } std::sort(ids.begin(), ids.end()); for (size_t i = 0; i < kNumThreads * kNumElements; ++i) { EXPECT_EQ(i, ids[i]); } for (auto& thread : threads) { thread.join(); } }