blob: 1814b6cd81fe2b0025a965603f7813ad47b08f0a [file] [log] [blame]
cfredrica0464ebf2021-07-24 01:26:391// 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
5#ifndef BASE_BARRIER_CALLBACK_H_
6#define BASE_BARRIER_CALLBACK_H_
7
Sumaid Syed22f60eeb2021-08-26 05:16:268#include <memory>
cfredrica0464ebf2021-07-24 01:26:399#include <type_traits>
Sumaid Syed22f60eeb2021-08-26 05:16:2610#include <utility>
cfredrica0464ebf2021-07-24 01:26:3911#include <vector>
12
13#include "base/bind.h"
14#include "base/callback.h"
15#include "base/callback_helpers.h"
16#include "base/synchronization/lock.h"
cfredricc8cdd1d2021-08-11 00:01:4817#include "base/template_util.h"
cfredrica0464ebf2021-07-24 01:26:3918#include "base/thread_annotations.h"
19
20namespace base {
21
cfredric8c677a12021-08-03 21:48:3022namespace internal {
cfredrica0464ebf2021-07-24 01:26:3923
cfredricc8cdd1d2021-08-11 00:01:4824template <typename T, typename DoneArg>
cfredrica0464ebf2021-07-24 01:26:3925class BarrierCallbackInfo {
26 public:
27 BarrierCallbackInfo(size_t num_callbacks,
cfredricc8cdd1d2021-08-11 00:01:4828 OnceCallback<void(DoneArg)> done_callback)
cfredrica0464ebf2021-07-24 01:26:3929 : num_callbacks_left_(num_callbacks),
30 done_callback_(std::move(done_callback)) {
31 results_.reserve(num_callbacks);
32 }
33
34 void Run(T t) LOCKS_EXCLUDED(mutex_) {
35 base::ReleasableAutoLock lock(&mutex_);
36 DCHECK_NE(num_callbacks_left_, 0U);
37 results_.push_back(std::move(t));
38 --num_callbacks_left_;
39
40 if (num_callbacks_left_ == 0) {
cfredricc8cdd1d2021-08-11 00:01:4841 std::vector<base::remove_cvref_t<T>> results = std::move(results_);
cfredrica0464ebf2021-07-24 01:26:3942 lock.Release();
43 std::move(done_callback_).Run(std::move(results));
44 }
45 }
46
47 private:
48 Lock mutex_;
49 size_t num_callbacks_left_ GUARDED_BY(mutex_);
cfredricc8cdd1d2021-08-11 00:01:4850 std::vector<base::remove_cvref_t<T>> results_ GUARDED_BY(mutex_);
51 OnceCallback<void(DoneArg)> done_callback_;
cfredrica0464ebf2021-07-24 01:26:3952};
53
cfredriceaafc6b2021-07-27 21:12:0154template <typename T>
55void ShouldNeverRun(T t) {
56 CHECK(false);
57}
58
cfredric8c677a12021-08-03 21:48:3059} // namespace internal
cfredrica0464ebf2021-07-24 01:26:3960
61// BarrierCallback<T> is an analog of BarrierClosure for which each `Run()`
62// invocation takes a `T` as an argument. After `num_callbacks` such
63// invocations, BarrierCallback invokes `Run()` on its `done_callback`, passing
64// the vector of `T`s as an argument. (The ordering of the vector is
65// unspecified.)
66//
cfredricc8cdd1d2021-08-11 00:01:4867// `T`s that are movable are moved into the callback's storage; otherwise the T
68// is copied. (BarrierCallback does not support `T`s that are neither movable
69// nor copyable.) If T is a reference, the reference is removed, and the
70// callback moves or copies the underlying value per the previously stated rule.
71//
cfredriceaafc6b2021-07-27 21:12:0172// If `num_callbacks` is 0, `done_callback` is executed immediately.
cfredrica0464ebf2021-07-24 01:26:3973//
cfredricc8cdd1d2021-08-11 00:01:4874// `done_callback` may accept a `std::vector<T>`, `const std::vector<T>`, or
75// `const std::vector<T>&`.
76//
cfredrica0464ebf2021-07-24 01:26:3977// BarrierCallback is thread-safe - the internals are protected by a
78// `base::Lock`. `done_callback` will be run on the thread that calls the final
79// Run() on the returned callbacks, or the thread that constructed the
80// BarrierCallback (in the case where `num_callbacks` is 0).
81//
82// `done_callback` is also cleared on the thread that runs it (by virtue of
83// being a OnceCallback).
cfredricc8cdd1d2021-08-11 00:01:4884template <typename T,
85 typename RawArg = base::remove_cvref_t<T>,
86 typename DoneArg = std::vector<RawArg>,
87 template <typename>
88 class CallbackType,
89 typename std::enable_if<std::is_same<
90 std::vector<RawArg>,
91 base::remove_cvref_t<DoneArg>>::value>::type* = nullptr,
92 typename = base::EnableIfIsBaseCallback<CallbackType>>
cfredrica0464ebf2021-07-24 01:26:3993RepeatingCallback<void(T)> BarrierCallback(
94 size_t num_callbacks,
cfredricc8cdd1d2021-08-11 00:01:4895 CallbackType<void(DoneArg)> done_callback) {
cfredriceaafc6b2021-07-27 21:12:0196 if (num_callbacks == 0) {
97 std::move(done_callback).Run({});
cfredric8c677a12021-08-03 21:48:3098 return BindRepeating(&internal::ShouldNeverRun<T>);
cfredriceaafc6b2021-07-27 21:12:0199 }
cfredrica0464ebf2021-07-24 01:26:39100
cfredricc8cdd1d2021-08-11 00:01:48101 return BindRepeating(
102 &internal::BarrierCallbackInfo<T, DoneArg>::Run,
103 std::make_unique<internal::BarrierCallbackInfo<T, DoneArg>>(
104 num_callbacks, std::move(done_callback)));
cfredrica0464ebf2021-07-24 01:26:39105}
106
107} // namespace base
108
109#endif // BASE_BARRIER_CALLBACK_H_