blob: 88a5bc000253bda270d58223955703b0be7e8d3f [file] [log] [blame]
Ilya Biryukov08e6ccb2017-10-09 16:26:26 +00001//===--- Function.h - Utility callable wrappers -----------------*- C++-*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
Benjamin Kramerc36c09f2018-07-03 20:59:33 +000010// This file provides utilities for callable objects.
Ilya Biryukov08e6ccb2017-10-09 16:26:26 +000011//
12//===----------------------------------------------------------------------===//
13
14#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_FUNCTION_H
15#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_FUNCTION_H
16
Benjamin Kramerc36c09f2018-07-03 20:59:33 +000017#include "llvm/ADT/FunctionExtras.h"
Sam McCalla7bb0cc2018-03-12 23:22:35 +000018#include "llvm/Support/Error.h"
Ilya Biryukov08e6ccb2017-10-09 16:26:26 +000019#include <tuple>
Ilya Biryukov08e6ccb2017-10-09 16:26:26 +000020#include <utility>
21
22namespace clang {
23namespace clangd {
24
Sam McCalla7bb0cc2018-03-12 23:22:35 +000025/// A Callback<T> is a void function that accepts Expected<T>.
26/// This is accepted by ClangdServer functions that logically return T.
Benjamin Kramerc36c09f2018-07-03 20:59:33 +000027template <typename T>
28using Callback = llvm::unique_function<void(llvm::Expected<T>)>;
Ilya Biryukov08e6ccb2017-10-09 16:26:26 +000029
30/// Stores a callable object (Func) and arguments (Args) and allows to call the
31/// callable with provided arguments later using `operator ()`. The arguments
32/// are std::forward'ed into the callable in the body of `operator()`. Therefore
33/// `operator()` can only be called once, as some of the arguments could be
34/// std::move'ed into the callable on first call.
35template <class Func, class... Args> struct ForwardBinder {
36 using Tuple = std::tuple<typename std::decay<Func>::type,
37 typename std::decay<Args>::type...>;
38 Tuple FuncWithArguments;
39#ifndef NDEBUG
40 bool WasCalled = false;
41#endif
42
43public:
44 ForwardBinder(Tuple FuncWithArguments)
45 : FuncWithArguments(std::move(FuncWithArguments)) {}
46
47private:
48 template <std::size_t... Indexes, class... RestArgs>
49 auto CallImpl(llvm::integer_sequence<std::size_t, Indexes...> Seq,
50 RestArgs &&... Rest)
51 -> decltype(std::get<0>(this->FuncWithArguments)(
52 std::forward<Args>(std::get<Indexes + 1>(this->FuncWithArguments))...,
53 std::forward<RestArgs>(Rest)...)) {
54 return std::get<0>(this->FuncWithArguments)(
55 std::forward<Args>(std::get<Indexes + 1>(this->FuncWithArguments))...,
56 std::forward<RestArgs>(Rest)...);
57 }
58
59public:
60 template <class... RestArgs>
61 auto operator()(RestArgs &&... Rest)
Ilya Biryukov4923a802017-10-10 08:40:57 +000062 -> decltype(this->CallImpl(llvm::index_sequence_for<Args...>(),
63 std::forward<RestArgs>(Rest)...)) {
Ilya Biryukov08e6ccb2017-10-09 16:26:26 +000064
65#ifndef NDEBUG
Sam McCall091557d2018-02-23 07:54:17 +000066 assert(!WasCalled && "Can only call result of Bind once.");
Ilya Biryukov08e6ccb2017-10-09 16:26:26 +000067 WasCalled = true;
68#endif
69 return CallImpl(llvm::index_sequence_for<Args...>(),
70 std::forward<RestArgs>(Rest)...);
71 }
72};
73
74/// Creates an object that stores a callable (\p F) and first arguments to the
75/// callable (\p As) and allows to call \p F with \Args at a later point.
76/// Similar to std::bind, but also works with move-only \p F and \p As.
77///
78/// The returned object must be called no more than once, as \p As are
79/// std::forwarded'ed (therefore can be moved) into \p F during the call.
80template <class Func, class... Args>
Sam McCall091557d2018-02-23 07:54:17 +000081ForwardBinder<Func, Args...> Bind(Func F, Args &&... As) {
Ilya Biryukov08e6ccb2017-10-09 16:26:26 +000082 return ForwardBinder<Func, Args...>(
83 std::make_tuple(std::forward<Func>(F), std::forward<Args>(As)...));
84}
85
Ilya Biryukov08e6ccb2017-10-09 16:26:26 +000086} // namespace clangd
87} // namespace clang
88
89#endif