blob: 0a38378e7149200cb8b2cc3fc37e1e36ee6350ee [file] [log] [blame]
// Copyright 2016 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 FBL_AUTO_CALL_H_
#define FBL_AUTO_CALL_H_
#include <fbl/macros.h>
#include <utility>
// RAII class to automatically call a function-like thing as it goes out of
// scope
//
// Examples:
//
// extern int foo();
// int a;
//
// auto ac = fbl::MakeAutoCall([&](){ a = 1; });
// auto ac2 = fbl::MakeAutoCall(foo);
//
// auto func = [&](){ a = 2; };
// fbl::AutoCall<decltype(func)> ac3(func);
// fbl::AutoCall<decltype(&foo)> ac4(&foo);
//
// // abort the call
// ac2.cancel();
namespace fbl {
template <typename T>
class AutoCall {
public:
constexpr explicit AutoCall(T c) : call_(std::move(c)) {}
~AutoCall() { call(); }
// move semantics
AutoCall(AutoCall&& c) : call_(std::move(c.call_)), active_(c.active_) { c.cancel(); }
AutoCall& operator=(AutoCall&& c) {
call();
call_ = std::move(c.call_);
active_ = c.active_;
c.cancel();
return *this;
}
// no copy
DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(AutoCall);
// cancel the eventual call
void cancel() { active_ = false; }
// call it immediately
void call() {
// Reset |active_| first to handle recursion (in the unlikely case it
// should happen).
bool active = active_;
cancel();
if (active)
(call_)();
}
private:
T call_;
bool active_ = true;
};
// helper routine to create an autocall object without needing template
// specialization
template <typename T>
inline AutoCall<T> MakeAutoCall(T c) {
return AutoCall<T>(std::move(c));
}
} // namespace fbl
#endif // FBL_AUTO_CALL_H_