diff --git a/folly/AtomicLinkedList.h b/folly/AtomicLinkedList.h index a644dbe6024..7c5a252e88c 100644 --- a/folly/AtomicLinkedList.h +++ b/folly/AtomicLinkedList.h @@ -75,6 +75,23 @@ class AtomicLinkedList { }); } + /** + * Sweeps the list a single time, as a single point in time swap with the + * current contents of the list. + * + * Unlike sweep() it does not loop to ensure the list is empty at some point + * after the last invocation. + * + * Returns false if the list is empty. + */ + template + bool sweepOnce(F&& func) { + return list_.sweepOnce([&](Wrapper* wrappedPtr) { + std::unique_ptr wrapper(wrappedPtr); + func(std::move(wrapper->data)); + }); + } + /** * Similar to sweep() but calls func() on elements in LIFO order. * diff --git a/folly/test/AtomicLinkedListTest.cpp b/folly/test/AtomicLinkedListTest.cpp index ddd1a7ce951..de3237db554 100644 --- a/folly/test/AtomicLinkedListTest.cpp +++ b/folly/test/AtomicLinkedListTest.cpp @@ -334,3 +334,26 @@ TEST(AtomicLinkedList, MoveAssignment) { EXPECT_TRUE(lastList.empty()); EXPECT_EQ(0, TestObject::numInstances()); } + +TEST(AtomicLinkedList, SweepOnce) { + folly::AtomicLinkedList list; + int a(1), b(2), c(3); + + list.insertHead(a); + list.insertHead(b); + list.insertHead(c); + + size_t id = 1; + list.sweepOnce([&](int&& obj) { + EXPECT_EQ(id, obj); + ++id; + }); + + EXPECT_TRUE(list.empty()); + + // Test that we can still insert + list.insertHead(a); + + EXPECT_FALSE(list.empty()); + list.sweepOnce([](int&& obj) { EXPECT_EQ(1, obj); }); +}