//===--- Function.h - Utility callable wrappers -----------------*- C++-*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file provides an analogue to std::function that supports move semantics. // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_FUNCTION_H #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_FUNCTION_H #include "llvm/ADT/STLExtras.h" #include #include #include #include #include namespace clang { namespace clangd { /// A move-only type-erasing function wrapper. Similar to `std::function`, but /// allows to store move-only callables. template class UniqueFunction; template class UniqueFunction { public: UniqueFunction() = default; UniqueFunction(std::nullptr_t) : UniqueFunction(){}; UniqueFunction(UniqueFunction const &) = delete; UniqueFunction &operator=(UniqueFunction const &) = delete; UniqueFunction(UniqueFunction &&) noexcept = default; UniqueFunction &operator=(UniqueFunction &&) noexcept = default; template ()(std::declval()...)), Ret>::value>::type> UniqueFunction(Callable &&Func) : CallablePtr(llvm::make_unique< FunctionCallImpl::type>>( std::forward(Func))) {} explicit operator bool() { return bool(CallablePtr); } Ret operator()(Args... As) { assert(CallablePtr); return CallablePtr->Call(std::forward(As)...); } private: class FunctionCallBase { public: virtual ~FunctionCallBase() = default; virtual Ret Call(Args... As) = 0; }; template class FunctionCallImpl final : public FunctionCallBase { static_assert( std::is_same::type>::value, "FunctionCallImpl must be instanstiated with std::decay'ed types"); public: FunctionCallImpl(Callable Func) : Func(std::move(Func)) {} Ret Call(Args... As) override { return Func(std::forward(As)...); } private: Callable Func; }; std::unique_ptr CallablePtr; }; /// Stores a callable object (Func) and arguments (Args) and allows to call the /// callable with provided arguments later using `operator ()`. The arguments /// are std::forward'ed into the callable in the body of `operator()`. Therefore /// `operator()` can only be called once, as some of the arguments could be /// std::move'ed into the callable on first call. template struct ForwardBinder { using Tuple = std::tuple::type, typename std::decay::type...>; Tuple FuncWithArguments; #ifndef NDEBUG bool WasCalled = false; #endif public: ForwardBinder(Tuple FuncWithArguments) : FuncWithArguments(std::move(FuncWithArguments)) {} private: template auto CallImpl(llvm::integer_sequence Seq, RestArgs &&... Rest) -> decltype(std::get<0>(this->FuncWithArguments)( std::forward(std::get(this->FuncWithArguments))..., std::forward(Rest)...)) { return std::get<0>(this->FuncWithArguments)( std::forward(std::get(this->FuncWithArguments))..., std::forward(Rest)...); } public: template auto operator()(RestArgs &&... Rest) -> decltype(this->CallImpl(llvm::index_sequence_for(), std::forward(Rest)...)) { #ifndef NDEBUG assert(!WasCalled && "Can only call result of BindWithForward once."); WasCalled = true; #endif return CallImpl(llvm::index_sequence_for(), std::forward(Rest)...); } }; /// Creates an object that stores a callable (\p F) and first arguments to the /// callable (\p As) and allows to call \p F with \Args at a later point. /// Similar to std::bind, but also works with move-only \p F and \p As. /// /// The returned object must be called no more than once, as \p As are /// std::forwarded'ed (therefore can be moved) into \p F during the call. template ForwardBinder BindWithForward(Func F, Args &&... As) { return ForwardBinder( std::make_tuple(std::forward(F), std::forward(As)...)); } namespace detail { /// Runs provided callback in destructor. Use onScopeExit helper function to /// create this object. template struct ScopeExitGuard { static_assert(std::is_same::type, Func>::value, "Func must be decayed"); ScopeExitGuard(Func F) : F(std::move(F)) {} ~ScopeExitGuard() { if (!F) return; (*F)(); } // Move-only. ScopeExitGuard(const ScopeExitGuard &) = delete; ScopeExitGuard &operator=(const ScopeExitGuard &) = delete; ScopeExitGuard(ScopeExitGuard &&Other) = default; ScopeExitGuard &operator=(ScopeExitGuard &&Other) = default; private: llvm::Optional F; }; } // namespace detail /// Creates a RAII object that will run \p F in its destructor. template auto onScopeExit(Func &&F) -> detail::ScopeExitGuard::type> { return detail::ScopeExitGuard::type>( std::forward(F)); } } // namespace clangd } // namespace clang #endif