Line data Source code
1 : //===--- 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 : //
10 : // This file provides utilities for callable objects.
11 : //
12 : //===----------------------------------------------------------------------===//
13 :
14 : #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_FUNCTION_H
15 : #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_FUNCTION_H
16 :
17 : #include "llvm/ADT/FunctionExtras.h"
18 : #include "llvm/Support/Error.h"
19 : #include <tuple>
20 : #include <utility>
21 :
22 : namespace clang {
23 : namespace clangd {
24 :
25 : /// A Callback<T> is a void function that accepts Expected<T>.
26 : /// This is accepted by ClangdServer functions that logically return T.
27 : template <typename T>
28 : using Callback = llvm::unique_function<void(llvm::Expected<T>)>;
29 :
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.
35 0 : template <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 :
43 : public:
44 : ForwardBinder(Tuple FuncWithArguments)
45 : : FuncWithArguments(std::move(FuncWithArguments)) {}
46 :
47 : private:
48 : template <std::size_t... Indexes, class... RestArgs>
49 0 : 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 0 : return std::get<0>(this->FuncWithArguments)(
55 : std::forward<Args>(std::get<Indexes + 1>(this->FuncWithArguments))...,
56 0 : std::forward<RestArgs>(Rest)...);
57 : }
58 0 :
59 : public:
60 : template <class... RestArgs>
61 : auto operator()(RestArgs &&... Rest)
62 : -> decltype(this->CallImpl(llvm::index_sequence_for<Args...>(),
63 0 : std::forward<RestArgs>(Rest)...)) {
64 :
65 0 : #ifndef NDEBUG
66 : assert(!WasCalled && "Can only call result of Bind once.");
67 0 : WasCalled = true;
68 : #endif
69 : return CallImpl(llvm::index_sequence_for<Args...>(),
70 : std::forward<RestArgs>(Rest)...);
71 : }
72 0 : };
73 :
74 0 : /// 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 0 : /// 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.
80 : template <class Func, class... Args>
81 0 : ForwardBinder<Func, Args...> Bind(Func F, Args &&... As) {
82 : return ForwardBinder<Func, Args...>(
83 0 : std::make_tuple(std::forward<Func>(F), std::forward<Args>(As)...));
84 : }
85 0 :
86 : } // namespace clangd
87 : } // namespace clang
88 :
89 : #endif
|