/*
- * Copyright 2016 Facebook, Inc.
+ * Copyright 2017 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include <atomic>
#include <cassert>
+#include <utility>
namespace folly {
void sweep(F&& func) {
while (auto head = head_.exchange(nullptr)) {
auto rhead = reverse(head);
- while (rhead != nullptr) {
- auto t = rhead;
- rhead = next(t);
- next(t) = nullptr;
- func(t);
- }
+ unlinkAll(rhead, std::forward<F>(func));
}
}
+ /**
+ * Similar to sweep() but calls func() on elements in LIFO order.
+ *
+ * func() is called for all elements in the list at the moment
+ * reverseSweep() is called. Unlike sweep() it does not loop to ensure the
+ * list is empty at some point after the last invocation. This way callers
+ * can reason about the ordering: elements inserted since the last call to
+ * reverseSweep() will be provided in LIFO order.
+ *
+ * Example: if elements are inserted in the order 1-2-3, the callback is
+ * invoked 3-2-1. If the callback moves elements onto a stack, popping off
+ * the stack will produce the original insertion order 1-2-3.
+ */
+ template <typename F>
+ void reverseSweep(F&& func) {
+ // We don't loop like sweep() does because the overall order of callbacks
+ // would be strand-wise LIFO which is meaningless to callers.
+ auto head = head_.exchange(nullptr);
+ unlinkAll(head, std::forward<F>(func));
+ }
+
private:
std::atomic<T*> head_{nullptr};
}
return rhead;
}
+
+ /* Unlinks all elements in the linked list fragment pointed to by `head',
+ * calling func() on every element */
+ template <typename F>
+ void unlinkAll(T* head, F&& func) {
+ while (head != nullptr) {
+ auto t = head;
+ head = next(t);
+ next(t) = nullptr;
+ func(t);
+ }
+ }
};
} // namespace folly