aboutsummaryrefslogtreecommitdiff
path: root/third_party/fuchsia/repo/sdk/lib/fit/include/lib/fit/defer.h
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/fuchsia/repo/sdk/lib/fit/include/lib/fit/defer.h')
-rw-r--r--third_party/fuchsia/repo/sdk/lib/fit/include/lib/fit/defer.h145
1 files changed, 145 insertions, 0 deletions
diff --git a/third_party/fuchsia/repo/sdk/lib/fit/include/lib/fit/defer.h b/third_party/fuchsia/repo/sdk/lib/fit/include/lib/fit/defer.h
new file mode 100644
index 000000000..907a3b77e
--- /dev/null
+++ b/third_party/fuchsia/repo/sdk/lib/fit/include/lib/fit/defer.h
@@ -0,0 +1,145 @@
+// Copyright 2018 The Fuchsia 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 LIB_FIT_DEFER_H_
+#define LIB_FIT_DEFER_H_
+
+#include <utility>
+
+#include "function.h"
+#include "nullable.h"
+
+namespace fit {
+
+// A move-only deferred action wrapper with RAII semantics.
+// This class is not thread safe.
+//
+// The wrapper holds a function-like callable target with no arguments
+// which it invokes when it goes out of scope unless canceled, called, or
+// moved to a wrapper in a different scope.
+//
+// See |fit::defer()| for idiomatic usage.
+template <typename T>
+class deferred_action final {
+ public:
+ // Creates a deferred action without a pending target.
+ deferred_action() = default;
+ explicit deferred_action(decltype(nullptr)) {}
+
+ // Creates a deferred action with a pending target.
+ explicit deferred_action(T target) : target_(std::move(target)) {}
+
+ // Creates a deferred action with a pending target moved from another
+ // deferred action, leaving the other one without a pending target.
+ deferred_action(deferred_action&& other) : target_(std::move(other.target_)) {
+ other.target_.reset();
+ }
+
+ // Invokes and releases the deferred action's pending target (if any).
+ ~deferred_action() { call(); }
+
+ // Returns true if the deferred action has a pending target.
+ explicit operator bool() const { return !!target_; }
+
+ // Invokes and releases the deferred action's pending target (if any),
+ // then move-assigns it from another deferred action, leaving the latter
+ // one without a pending target.
+ deferred_action& operator=(deferred_action&& other) {
+ if (&other == this)
+ return *this;
+ call();
+ target_ = std::move(other.target_);
+ other.target_.reset();
+ return *this;
+ }
+
+ // Invokes and releases the deferred action's pending target (if any).
+ void call() {
+ if (target_) {
+ // Move to a local to guard against re-entrance.
+ T local_target = std::move(*target_);
+ target_.reset();
+ local_target();
+ }
+ }
+
+ // Releases the deferred action's pending target (if any) without
+ // invoking it.
+ void cancel() { target_.reset(); }
+ deferred_action& operator=(decltype(nullptr)) {
+ cancel();
+ return *this;
+ }
+
+ // Assigns a new target to the deferred action.
+ deferred_action& operator=(T target) {
+ target_ = std::move(target);
+ return *this;
+ }
+
+ deferred_action(const deferred_action& other) = delete;
+ deferred_action& operator=(const deferred_action& other) = delete;
+
+ private:
+ nullable<T> target_;
+};
+
+template <typename T>
+bool operator==(const deferred_action<T>& action, decltype(nullptr)) {
+ return !action;
+}
+template <typename T>
+bool operator==(decltype(nullptr), const deferred_action<T>& action) {
+ return !action;
+}
+template <typename T>
+bool operator!=(const deferred_action<T>& action, decltype(nullptr)) {
+ return !!action;
+}
+template <typename T>
+bool operator!=(decltype(nullptr), const deferred_action<T>& action) {
+ return !!action;
+}
+
+// Defers execution of a function-like callable target with no arguments
+// until the value returned by this function goes out of scope unless canceled,
+// called, or moved to a wrapper in a different scope.
+//
+// // This example prints "Hello..." then "Goodbye!".
+// void test() {
+// auto d = fit::defer([]{ puts("Goodbye!"); });
+// puts("Hello...");
+// }
+//
+// // This example prints nothing because the deferred action is canceled.
+// void do_nothing() {
+// auto d = fit::defer([]{ puts("I'm not here."); });
+// d.cancel();
+// }
+//
+// // This example shows how the deferred action can be reassigned assuming
+// // the new target has the same type and the old one, in this case by
+// // representing the target as a |fit::closure|.
+// void reassign() {
+// auto d = fit::defer<fit::closure>([] { puts("This runs first."); });
+// d = fit::defer<fit::closure>([] { puts("This runs afterwards."); });
+// }
+template <typename T>
+__attribute__((__warn_unused_result__)) inline deferred_action<T> defer(T target) {
+ return deferred_action<T>(std::move(target));
+}
+
+// Alias for a deferred_action using a fit::callback.
+using deferred_callback = deferred_action<fit::callback<void()>>;
+
+// Defers execution of a fit::callback with no arguments. See |fit::defer| for
+// details.
+__attribute__((__warn_unused_result__)) inline deferred_callback defer_callback(
+ fit::callback<void()> target) {
+ return deferred_callback(std::move(target));
+}
+
+} // namespace fit
+
+#endif // LIB_FIT_DEFER_H_