barrier_callback.h 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. // Copyright 2021 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #ifndef BASE_BARRIER_CALLBACK_H_
  5. #define BASE_BARRIER_CALLBACK_H_
  6. #include <memory>
  7. #include <type_traits>
  8. #include <utility>
  9. #include <vector>
  10. #include "base/bind.h"
  11. #include "base/callback.h"
  12. #include "base/callback_helpers.h"
  13. #include "base/check.h"
  14. #include "base/check_op.h"
  15. #include "base/synchronization/lock.h"
  16. #include "base/template_util.h"
  17. #include "base/thread_annotations.h"
  18. namespace base {
  19. namespace internal {
  20. template <typename T, typename DoneArg>
  21. class BarrierCallbackInfo {
  22. public:
  23. BarrierCallbackInfo(size_t num_callbacks,
  24. OnceCallback<void(DoneArg)> done_callback)
  25. : num_callbacks_left_(num_callbacks),
  26. done_callback_(std::move(done_callback)) {
  27. results_.reserve(num_callbacks);
  28. }
  29. void Run(T t) LOCKS_EXCLUDED(mutex_) {
  30. base::ReleasableAutoLock lock(&mutex_);
  31. DCHECK_NE(num_callbacks_left_, 0U);
  32. results_.push_back(std::move(t));
  33. --num_callbacks_left_;
  34. if (num_callbacks_left_ == 0) {
  35. std::vector<base::remove_cvref_t<T>> results = std::move(results_);
  36. lock.Release();
  37. std::move(done_callback_).Run(std::move(results));
  38. }
  39. }
  40. private:
  41. Lock mutex_;
  42. size_t num_callbacks_left_ GUARDED_BY(mutex_);
  43. std::vector<base::remove_cvref_t<T>> results_ GUARDED_BY(mutex_);
  44. OnceCallback<void(DoneArg)> done_callback_;
  45. };
  46. template <typename T>
  47. void ShouldNeverRun(T t) {
  48. CHECK(false);
  49. }
  50. } // namespace internal
  51. // BarrierCallback<T> is an analog of BarrierClosure for which each `Run()`
  52. // invocation takes a `T` as an argument. After `num_callbacks` such
  53. // invocations, BarrierCallback invokes `Run()` on its `done_callback`, passing
  54. // the vector of `T`s as an argument. (The ordering of the vector is
  55. // unspecified.)
  56. //
  57. // `T`s that are movable are moved into the callback's storage; otherwise the T
  58. // is copied. (BarrierCallback does not support `T`s that are neither movable
  59. // nor copyable.) If T is a reference, the reference is removed, and the
  60. // callback moves or copies the underlying value per the previously stated rule.
  61. // Beware of creating dangling references. Types that contain references but are
  62. // not references themselves are not modified for callback storage, e.g.
  63. // `std::pair<int, const Foo&>`. Dangling references will be passed to
  64. // `done_callback` if the referenced `Foo` objects have already been deleted.
  65. //
  66. // If `num_callbacks` is 0, `done_callback` is executed immediately.
  67. //
  68. // `done_callback` may accept a `std::vector<T>`, `const std::vector<T>`, or
  69. // `const std::vector<T>&`.
  70. //
  71. // BarrierCallback is thread-safe - the internals are protected by a
  72. // `base::Lock`. `done_callback` will be run on the thread that calls the final
  73. // Run() on the returned callbacks, or the thread that constructed the
  74. // BarrierCallback (in the case where `num_callbacks` is 0).
  75. //
  76. // BarrierCallback is copyable. Copies share state.
  77. //
  78. // `done_callback` is also cleared on the thread that runs it (by virtue of
  79. // being a OnceCallback).
  80. //
  81. // See also
  82. // https://chromium.googlesource.com/chromium/src/+/HEAD/docs/callback.md
  83. template <typename T,
  84. typename RawArg = base::remove_cvref_t<T>,
  85. typename DoneArg = std::vector<RawArg>,
  86. template <typename>
  87. class CallbackType,
  88. typename std::enable_if<std::is_same<
  89. std::vector<RawArg>,
  90. base::remove_cvref_t<DoneArg>>::value>::type* = nullptr,
  91. typename = base::EnableIfIsBaseCallback<CallbackType>>
  92. RepeatingCallback<void(T)> BarrierCallback(
  93. size_t num_callbacks,
  94. CallbackType<void(DoneArg)> done_callback) {
  95. if (num_callbacks == 0) {
  96. std::move(done_callback).Run({});
  97. return BindRepeating(&internal::ShouldNeverRun<T>);
  98. }
  99. return BindRepeating(
  100. &internal::BarrierCallbackInfo<T, DoneArg>::Run,
  101. std::make_unique<internal::BarrierCallbackInfo<T, DoneArg>>(
  102. num_callbacks, std::move(done_callback)));
  103. }
  104. } // namespace base
  105. #endif // BASE_BARRIER_CALLBACK_H_