• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 // Copyright 2018 The Fuchsia Authors. All rights reserved.
16 // Use of this source code is governed by a BSD-style license that can be
17 // found in the LICENSE file.
18 
19 #pragma once
20 
21 #include <utility>
22 
23 #include "Function.h"
24 #include "Nullable.h"
25 
26 namespace gfxstream::guest {
27 namespace fit {
28 
29 // A move-only deferred action wrapper with RAII semantics.
30 // This class is not thread safe.
31 //
32 // The wrapper holds a function-like callable target with no arguments
33 // which it invokes when it goes out of scope unless canceled, called, or
34 // moved to a wrapper in a different scope.
35 //
36 // See |fit::defer()| for idiomatic usage.
37 template <typename T>
38 class DeferredAction final {
39 public:
40     // Creates a deferred action without a pending target.
41     DeferredAction() = default;
DeferredAction(decltype (nullptr))42     explicit DeferredAction(decltype(nullptr)) {}
43 
44     // Creates a deferred action with a pending target.
DeferredAction(T target)45     explicit DeferredAction(T target) : mTarget(std::move(target)) {}
46 
47     // Creates a deferred action with a pending target moved from another
48     // deferred action, leaving the other one without a pending target.
DeferredAction(DeferredAction && other)49     DeferredAction(DeferredAction&& other) : mTarget(std::move(other.mTarget)) {
50         other.mTarget.reset();
51     }
52 
53     // Invokes and releases the deferred action's pending target (if any).
~DeferredAction()54     ~DeferredAction() { call(); }
55 
56     // Returns true if the deferred action has a pending target.
57     explicit operator bool() const { return !!mTarget; }
58 
59     // Invokes and releases the deferred action's pending target (if any),
60     // then move-assigns it from another deferred action, leaving the latter
61     // one without a pending target.
62     DeferredAction& operator=(DeferredAction&& other) {
63         if (&other == this)
64             return *this;
65         call();
66         mTarget = std::move(other.mTarget);
67         other.mTarget.reset();
68         return *this;
69     }
70 
71     // Invokes and releases the deferred action's pending target (if any).
call()72     void call() {
73         if (mTarget) {
74             // Move to a local to guard against re-entrance.
75             T local_target = std::move(*mTarget);
76             mTarget.reset();
77             local_target();
78         }
79     }
80 
81     // Releases the deferred action's pending target (if any) without
82     // invoking it.
cancel()83     void cancel() { mTarget.reset(); }
decltype(nullptr)84     DeferredAction& operator=(decltype(nullptr)) {
85         cancel();
86         return *this;
87     }
88 
89     // Assigns a new target to the deferred action.
90     DeferredAction& operator=(T target) {
91         mTarget = std::move(target);
92         return *this;
93     }
94 
95     DeferredAction(const DeferredAction& other) = delete;
96     DeferredAction& operator=(const DeferredAction& other) = delete;
97 
98 private:
99     Nullable<T> mTarget;
100 };
101 
102 template <typename T>
103 bool operator==(const DeferredAction<T>& action, decltype(nullptr)) {
104     return !action;
105 }
106 template <typename T>
107 bool operator==(decltype(nullptr), const DeferredAction<T>& action) {
108     return !action;
109 }
110 template <typename T>
111 bool operator!=(const DeferredAction<T>& action, decltype(nullptr)) {
112     return !!action;
113 }
114 template <typename T>
115 bool operator!=(decltype(nullptr), const DeferredAction<T>& action) {
116     return !!action;
117 }
118 
119 // Defers execution of a function-like callable target with no arguments
120 // until the value returned by this function goes out of scope unless canceled,
121 // called, or moved to a wrapper in a different scope.
122 //
123 // // This example prints "Hello..." then "Goodbye!".
124 // void test() {
125 //     auto d = fit::defer([]{ puts("Goodbye!"); });
126 //     puts("Hello...");
127 // }
128 //
129 // // This example prints nothing because the deferred action is canceled.
130 // void do_nothing() {
131 //     auto d = fit::defer([]{ puts("I'm not here."); });
132 //     d.cancel();
133 // }
134 //
135 // // This example shows how the deferred action can be reassigned assuming
136 // // the new target has the same type and the old one, in this case by
137 // // representing the target as a |fit::Closure|.
138 // void reassign() {
139 //     auto d = fit::defer<fit::Closure>([] { puts("This runs first."); });
140 //     d = fit::defer<fit::Closure>([] { puts("This runs afterwards."); });
141 // }
142 template <typename T>
defer(T target)143 inline DeferredAction<T> defer(T target) {
144     return DeferredAction<T>(std::move(target));
145 }
146 
147 // Alias for a deferred_action using a fit::Callback.
148 using DeferredCallback = DeferredAction<fit::Callback<void()>>;
149 
150 // Defers execution of a fit::Callback with no arguments. See |fit::defer| for
151 // details.
deferCallback(fit::Callback<void ()> target)152 inline DeferredCallback deferCallback(fit::Callback<void()> target) {
153     return DeferredCallback(std::move(target));
154 }
155 
156 }  // namespace fit
157 }  // namespace gfxstream::guest
158