158 lines
5.1 KiB
C++
158 lines
5.1 KiB
C++
// Copyright 2021 The Android Open Source Project
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
// 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.
|
|
|
|
#pragma once
|
|
|
|
#include <utility>
|
|
|
|
#include "Function.h"
|
|
#include "Nullable.h"
|
|
|
|
namespace android::base {
|
|
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 DeferredAction final {
|
|
public:
|
|
// Creates a deferred action without a pending target.
|
|
DeferredAction() = default;
|
|
explicit DeferredAction(decltype(nullptr)) {}
|
|
|
|
// Creates a deferred action with a pending target.
|
|
explicit DeferredAction(T target) : mTarget(std::move(target)) {}
|
|
|
|
// Creates a deferred action with a pending target moved from another
|
|
// deferred action, leaving the other one without a pending target.
|
|
DeferredAction(DeferredAction&& other) : mTarget(std::move(other.mTarget)) {
|
|
other.mTarget.reset();
|
|
}
|
|
|
|
// Invokes and releases the deferred action's pending target (if any).
|
|
~DeferredAction() { call(); }
|
|
|
|
// Returns true if the deferred action has a pending target.
|
|
explicit operator bool() const { return !!mTarget; }
|
|
|
|
// 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.
|
|
DeferredAction& operator=(DeferredAction&& other) {
|
|
if (&other == this)
|
|
return *this;
|
|
call();
|
|
mTarget = std::move(other.mTarget);
|
|
other.mTarget.reset();
|
|
return *this;
|
|
}
|
|
|
|
// Invokes and releases the deferred action's pending target (if any).
|
|
void call() {
|
|
if (mTarget) {
|
|
// Move to a local to guard against re-entrance.
|
|
T local_target = std::move(*mTarget);
|
|
mTarget.reset();
|
|
local_target();
|
|
}
|
|
}
|
|
|
|
// Releases the deferred action's pending target (if any) without
|
|
// invoking it.
|
|
void cancel() { mTarget.reset(); }
|
|
DeferredAction& operator=(decltype(nullptr)) {
|
|
cancel();
|
|
return *this;
|
|
}
|
|
|
|
// Assigns a new target to the deferred action.
|
|
DeferredAction& operator=(T target) {
|
|
mTarget = std::move(target);
|
|
return *this;
|
|
}
|
|
|
|
DeferredAction(const DeferredAction& other) = delete;
|
|
DeferredAction& operator=(const DeferredAction& other) = delete;
|
|
|
|
private:
|
|
Nullable<T> mTarget;
|
|
};
|
|
|
|
template <typename T>
|
|
bool operator==(const DeferredAction<T>& action, decltype(nullptr)) {
|
|
return !action;
|
|
}
|
|
template <typename T>
|
|
bool operator==(decltype(nullptr), const DeferredAction<T>& action) {
|
|
return !action;
|
|
}
|
|
template <typename T>
|
|
bool operator!=(const DeferredAction<T>& action, decltype(nullptr)) {
|
|
return !!action;
|
|
}
|
|
template <typename T>
|
|
bool operator!=(decltype(nullptr), const DeferredAction<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>
|
|
inline DeferredAction<T> defer(T target) {
|
|
return DeferredAction<T>(std::move(target));
|
|
}
|
|
|
|
// Alias for a deferred_action using a fit::Callback.
|
|
using DeferredCallback = DeferredAction<fit::Callback<void()>>;
|
|
|
|
// Defers execution of a fit::Callback with no arguments. See |fit::defer| for
|
|
// details.
|
|
inline DeferredCallback deferCallback(fit::Callback<void()> target) {
|
|
return DeferredCallback(std::move(target));
|
|
}
|
|
|
|
} // namespace fit
|
|
} // namespace android::base
|