AtomicLinkedList.h 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. /*
  2. * Copyright 2014-present Facebook, Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #pragma once
  17. #include <folly/AtomicIntrusiveLinkedList.h>
  18. #include <folly/Memory.h>
  19. namespace folly {
  20. /**
  21. * A very simple atomic single-linked list primitive.
  22. *
  23. * Usage:
  24. *
  25. * AtomicLinkedList<MyClass> list;
  26. * list.insert(a);
  27. * list.sweep([] (MyClass& c) { doSomething(c); }
  28. */
  29. template <class T>
  30. class AtomicLinkedList {
  31. public:
  32. AtomicLinkedList() {}
  33. AtomicLinkedList(const AtomicLinkedList&) = delete;
  34. AtomicLinkedList& operator=(const AtomicLinkedList&) = delete;
  35. AtomicLinkedList(AtomicLinkedList&& other) noexcept = default;
  36. AtomicLinkedList& operator=(AtomicLinkedList&& other) = default;
  37. ~AtomicLinkedList() {
  38. sweep([](T&&) {});
  39. }
  40. bool empty() const {
  41. return list_.empty();
  42. }
  43. /**
  44. * Atomically insert t at the head of the list.
  45. * @return True if the inserted element is the only one in the list
  46. * after the call.
  47. */
  48. bool insertHead(T t) {
  49. auto wrapper = std::make_unique<Wrapper>(std::move(t));
  50. return list_.insertHead(wrapper.release());
  51. }
  52. /**
  53. * Repeatedly pops element from head,
  54. * and calls func() on the removed elements in the order from tail to head.
  55. * Stops when the list is empty.
  56. */
  57. template <typename F>
  58. void sweep(F&& func) {
  59. list_.sweep([&](Wrapper* wrapperPtr) mutable {
  60. std::unique_ptr<Wrapper> wrapper(wrapperPtr);
  61. func(std::move(wrapper->data));
  62. });
  63. }
  64. /**
  65. * Similar to sweep() but calls func() on elements in LIFO order.
  66. *
  67. * func() is called for all elements in the list at the moment
  68. * reverseSweep() is called. Unlike sweep() it does not loop to ensure the
  69. * list is empty at some point after the last invocation. This way callers
  70. * can reason about the ordering: elements inserted since the last call to
  71. * reverseSweep() will be provided in LIFO order.
  72. *
  73. * Example: if elements are inserted in the order 1-2-3, the callback is
  74. * invoked 3-2-1. If the callback moves elements onto a stack, popping off
  75. * the stack will produce the original insertion order 1-2-3.
  76. */
  77. template <typename F>
  78. void reverseSweep(F&& func) {
  79. list_.reverseSweep([&](Wrapper* wrapperPtr) mutable {
  80. std::unique_ptr<Wrapper> wrapper(wrapperPtr);
  81. func(std::move(wrapper->data));
  82. });
  83. }
  84. private:
  85. struct Wrapper {
  86. explicit Wrapper(T&& t) : data(std::move(t)) {}
  87. AtomicIntrusiveLinkedListHook<Wrapper> hook;
  88. T data;
  89. };
  90. AtomicIntrusiveLinkedList<Wrapper, &Wrapper::hook> list_;
  91. };
  92. } // namespace folly