summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIlya Biryukov <ibiryukov@google.com>2017-10-09 16:26:26 +0000
committerIlya Biryukov <ibiryukov@google.com>2017-10-09 16:26:26 +0000
commit08e6ccbcf3349121bf7eb8b9abe6610abcd452dd (patch)
treee185f546a8c01657581c193390ee0e316ee93e55
parent21c75912f5e354e7083d75ccb3dcef04c11a501f (diff)
downloadbcm5719-llvm-08e6ccbcf3349121bf7eb8b9abe6610abcd452dd.tar.gz
bcm5719-llvm-08e6ccbcf3349121bf7eb8b9abe6610abcd452dd.zip
[clangd] Added move-only function helpers.
Summary: They are now used in ClangdScheduler instead of deferred std::async computations. The results of `std::async` are much less effective and do not provide a good abstraction for similar purposes, i.e. for storing additional callbacks to clangd async tasks. The actual callback API will follow a bit later. Reviewers: klimek, bkramer, sammccall, krasimir Reviewed By: sammccall Subscribers: cfe-commits Differential Revision: https://reviews.llvm.org/D38627 llvm-svn: 315210
-rw-r--r--clang-tools-extra/clangd/ClangdServer.cpp4
-rw-r--r--clang-tools-extra/clangd/ClangdServer.h13
-rw-r--r--clang-tools-extra/clangd/Function.h136
3 files changed, 144 insertions, 9 deletions
diff --git a/clang-tools-extra/clangd/ClangdServer.cpp b/clang-tools-extra/clangd/ClangdServer.cpp
index a516415f967..f24b4c5fe45 100644
--- a/clang-tools-extra/clangd/ClangdServer.cpp
+++ b/clang-tools-extra/clangd/ClangdServer.cpp
@@ -99,7 +99,7 @@ ClangdScheduler::ClangdScheduler(unsigned AsyncThreadsCount)
for (unsigned I = 0; I < AsyncThreadsCount; ++I) {
Workers.push_back(std::thread([this]() {
while (true) {
- std::future<void> Request;
+ UniqueFunction<void()> Request;
// Pick request from the queue
{
@@ -120,7 +120,7 @@ ClangdScheduler::ClangdScheduler(unsigned AsyncThreadsCount)
RequestQueue.pop_front();
} // unlock Mutex
- Request.get();
+ Request();
}
}));
}
diff --git a/clang-tools-extra/clangd/ClangdServer.h b/clang-tools-extra/clangd/ClangdServer.h
index 8728c7c7581..f2023f84f8e 100644
--- a/clang-tools-extra/clangd/ClangdServer.h
+++ b/clang-tools-extra/clangd/ClangdServer.h
@@ -20,6 +20,7 @@
#include "llvm/ADT/StringRef.h"
#include "ClangdUnit.h"
+#include "Function.h"
#include "Protocol.h"
#include <condition_variable>
@@ -132,9 +133,8 @@ public:
{
std::lock_guard<std::mutex> Lock(Mutex);
- RequestQueue.push_front(std::async(std::launch::deferred,
- std::forward<Func>(F),
- std::forward<Args>(As)...));
+ RequestQueue.push_front(
+ BindWithForward(std::forward<Func>(F), std::forward<Args>(As)...));
}
RequestCV.notify_one();
}
@@ -149,9 +149,8 @@ public:
{
std::lock_guard<std::mutex> Lock(Mutex);
- RequestQueue.push_back(std::async(std::launch::deferred,
- std::forward<Func>(F),
- std::forward<Args>(As)...));
+ RequestQueue.push_back(
+ BindWithForward(std::forward<Func>(F), std::forward<Args>(As)...));
}
RequestCV.notify_one();
}
@@ -167,7 +166,7 @@ private:
bool Done = false;
/// A queue of requests. Elements of this vector are async computations (i.e.
/// results of calling std::async(std::launch::deferred, ...)).
- std::deque<std::future<void>> RequestQueue;
+ std::deque<UniqueFunction<void()>> RequestQueue;
/// Condition variable to wake up worker threads.
std::condition_variable RequestCV;
};
diff --git a/clang-tools-extra/clangd/Function.h b/clang-tools-extra/clangd/Function.h
new file mode 100644
index 00000000000..20aac4b5d09
--- /dev/null
+++ b/clang-tools-extra/clangd/Function.h
@@ -0,0 +1,136 @@
+//===--- 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 <tuple>
+#include <type_traits>
+#include <utility>
+
+namespace clang {
+namespace clangd {
+
+/// A move-only type-erasing function wrapper. Similar to `std::function`, but
+/// allows to store move-only callables.
+template <class> class UniqueFunction;
+
+template <class Ret, class... Args> class UniqueFunction<Ret(Args...)> {
+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 <class Callable>
+ UniqueFunction(Callable &&Func)
+ : CallablePtr(llvm::make_unique<
+ FunctionCallImpl<typename std::decay<Callable>::type>>(
+ std::forward<Callable>(Func))) {}
+
+ operator bool() { return CallablePtr; }
+
+ Ret operator()(Args... As) {
+ assert(CallablePtr);
+ CallablePtr->Call(std::forward<Args>(As)...);
+ }
+
+private:
+ class FunctionCallBase {
+ public:
+ virtual ~FunctionCallBase() = default;
+ virtual Ret Call(Args... As) = 0;
+ };
+
+ template <class Callable>
+ class FunctionCallImpl final : public FunctionCallBase {
+ static_assert(
+ std::is_same<Callable, typename std::decay<Callable>::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<Args>(As)...); }
+
+ private:
+ Callable Func;
+ };
+
+ std::unique_ptr<FunctionCallBase> 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 <class Func, class... Args> struct ForwardBinder {
+ using Tuple = std::tuple<typename std::decay<Func>::type,
+ typename std::decay<Args>::type...>;
+ Tuple FuncWithArguments;
+#ifndef NDEBUG
+ bool WasCalled = false;
+#endif
+
+public:
+ ForwardBinder(Tuple FuncWithArguments)
+ : FuncWithArguments(std::move(FuncWithArguments)) {}
+
+private:
+ template <std::size_t... Indexes, class... RestArgs>
+ auto CallImpl(llvm::integer_sequence<std::size_t, Indexes...> Seq,
+ RestArgs &&... Rest)
+ -> decltype(std::get<0>(this->FuncWithArguments)(
+ std::forward<Args>(std::get<Indexes + 1>(this->FuncWithArguments))...,
+ std::forward<RestArgs>(Rest)...)) {
+ return std::get<0>(this->FuncWithArguments)(
+ std::forward<Args>(std::get<Indexes + 1>(this->FuncWithArguments))...,
+ std::forward<RestArgs>(Rest)...);
+ }
+
+public:
+ template <class... RestArgs>
+ auto operator()(RestArgs &&... Rest)
+ -> decltype(CallImpl(llvm::index_sequence_for<Args...>(),
+ std::forward<RestArgs>(Rest)...)) {
+
+#ifndef NDEBUG
+ assert(!WasCalled && "Can only call result of BindWithForward once.");
+ WasCalled = true;
+#endif
+ return CallImpl(llvm::index_sequence_for<Args...>(),
+ std::forward<RestArgs>(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 <class Func, class... Args>
+ForwardBinder<Func, Args...> BindWithForward(Func F, Args &&... As) {
+ return ForwardBinder<Func, Args...>(
+ std::make_tuple(std::forward<Func>(F), std::forward<Args>(As)...));
+}
+
+} // namespace clangd
+} // namespace clang
+
+#endif
OpenPOWER on IntegriCloud