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