123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120 |
- // Copyright 2021 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #ifndef BASE_BARRIER_CALLBACK_H_
- #define BASE_BARRIER_CALLBACK_H_
- #include <memory>
- #include <type_traits>
- #include <utility>
- #include <vector>
- #include "base/bind.h"
- #include "base/callback.h"
- #include "base/callback_helpers.h"
- #include "base/check.h"
- #include "base/check_op.h"
- #include "base/synchronization/lock.h"
- #include "base/template_util.h"
- #include "base/thread_annotations.h"
- namespace base {
- namespace internal {
- template <typename T, typename DoneArg>
- class BarrierCallbackInfo {
- public:
- BarrierCallbackInfo(size_t num_callbacks,
- OnceCallback<void(DoneArg)> done_callback)
- : num_callbacks_left_(num_callbacks),
- done_callback_(std::move(done_callback)) {
- results_.reserve(num_callbacks);
- }
- void Run(T t) LOCKS_EXCLUDED(mutex_) {
- base::ReleasableAutoLock lock(&mutex_);
- DCHECK_NE(num_callbacks_left_, 0U);
- results_.push_back(std::move(t));
- --num_callbacks_left_;
- if (num_callbacks_left_ == 0) {
- std::vector<base::remove_cvref_t<T>> results = std::move(results_);
- lock.Release();
- std::move(done_callback_).Run(std::move(results));
- }
- }
- private:
- Lock mutex_;
- size_t num_callbacks_left_ GUARDED_BY(mutex_);
- std::vector<base::remove_cvref_t<T>> results_ GUARDED_BY(mutex_);
- OnceCallback<void(DoneArg)> done_callback_;
- };
- template <typename T>
- void ShouldNeverRun(T t) {
- CHECK(false);
- }
- } // namespace internal
- // BarrierCallback<T> is an analog of BarrierClosure for which each `Run()`
- // invocation takes a `T` as an argument. After `num_callbacks` such
- // invocations, BarrierCallback invokes `Run()` on its `done_callback`, passing
- // the vector of `T`s as an argument. (The ordering of the vector is
- // unspecified.)
- //
- // `T`s that are movable are moved into the callback's storage; otherwise the T
- // is copied. (BarrierCallback does not support `T`s that are neither movable
- // nor copyable.) If T is a reference, the reference is removed, and the
- // callback moves or copies the underlying value per the previously stated rule.
- // Beware of creating dangling references. Types that contain references but are
- // not references themselves are not modified for callback storage, e.g.
- // `std::pair<int, const Foo&>`. Dangling references will be passed to
- // `done_callback` if the referenced `Foo` objects have already been deleted.
- //
- // If `num_callbacks` is 0, `done_callback` is executed immediately.
- //
- // `done_callback` may accept a `std::vector<T>`, `const std::vector<T>`, or
- // `const std::vector<T>&`.
- //
- // BarrierCallback is thread-safe - the internals are protected by a
- // `base::Lock`. `done_callback` will be run on the thread that calls the final
- // Run() on the returned callbacks, or the thread that constructed the
- // BarrierCallback (in the case where `num_callbacks` is 0).
- //
- // BarrierCallback is copyable. Copies share state.
- //
- // `done_callback` is also cleared on the thread that runs it (by virtue of
- // being a OnceCallback).
- //
- // See also
- // https://chromium.googlesource.com/chromium/src/+/HEAD/docs/callback.md
- template <typename T,
- typename RawArg = base::remove_cvref_t<T>,
- typename DoneArg = std::vector<RawArg>,
- template <typename>
- class CallbackType,
- typename std::enable_if<std::is_same<
- std::vector<RawArg>,
- base::remove_cvref_t<DoneArg>>::value>::type* = nullptr,
- typename = base::EnableIfIsBaseCallback<CallbackType>>
- RepeatingCallback<void(T)> BarrierCallback(
- size_t num_callbacks,
- CallbackType<void(DoneArg)> done_callback) {
- if (num_callbacks == 0) {
- std::move(done_callback).Run({});
- return BindRepeating(&internal::ShouldNeverRun<T>);
- }
- return BindRepeating(
- &internal::BarrierCallbackInfo<T, DoneArg>::Run,
- std::make_unique<internal::BarrierCallbackInfo<T, DoneArg>>(
- num_callbacks, std::move(done_callback)));
- }
- } // namespace base
- #endif // BASE_BARRIER_CALLBACK_H_
|