[clang-tools-extra] r315210 - [clangd] Added move-only function helpers.

Galina Kistanova via cfe-commits cfe-commits at lists.llvm.org
Mon Oct 9 16:15:29 PDT 2017


Hello Ilya,

This commit broke build on one of our builders:

http://lab.llvm.org:8011/builders/clang-x86_64-linux-abi-test/builds/16435

Please have a look?

Thanks

Galina


On Mon, Oct 9, 2017 at 9:26 AM, Ilya Biryukov via cfe-commits <
cfe-commits at lists.llvm.org> wrote:

> Author: ibiryukov
> Date: Mon Oct  9 09:26:26 2017
> New Revision: 315210
>
> URL: http://llvm.org/viewvc/llvm-project?rev=315210&view=rev
> Log:
> [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
>
> Added:
>     clang-tools-extra/trunk/clangd/Function.h
> Modified:
>     clang-tools-extra/trunk/clangd/ClangdServer.cpp
>     clang-tools-extra/trunk/clangd/ClangdServer.h
>
> Modified: clang-tools-extra/trunk/clangd/ClangdServer.cpp
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/
> trunk/clangd/ClangdServer.cpp?rev=315210&r1=315209&r2=315210&view=diff
> ============================================================
> ==================
> --- clang-tools-extra/trunk/clangd/ClangdServer.cpp (original)
> +++ clang-tools-extra/trunk/clangd/ClangdServer.cpp Mon Oct  9 09:26:26
> 2017
> @@ -99,7 +99,7 @@ ClangdScheduler::ClangdScheduler(unsigne
>    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(unsigne
>            RequestQueue.pop_front();
>          } // unlock Mutex
>
> -        Request.get();
> +        Request();
>        }
>      }));
>    }
>
> Modified: clang-tools-extra/trunk/clangd/ClangdServer.h
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/
> trunk/clangd/ClangdServer.h?rev=315210&r1=315209&r2=315210&view=diff
> ============================================================
> ==================
> --- clang-tools-extra/trunk/clangd/ClangdServer.h (original)
> +++ clang-tools-extra/trunk/clangd/ClangdServer.h Mon Oct  9 09:26:26 2017
> @@ -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;
>  };
>
> Added: clang-tools-extra/trunk/clangd/Function.h
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/
> trunk/clangd/Function.h?rev=315210&view=auto
> ============================================================
> ==================
> --- clang-tools-extra/trunk/clangd/Function.h (added)
> +++ clang-tools-extra/trunk/clangd/Function.h Mon Oct  9 09:26:26 2017
> @@ -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
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20171009/863451bc/attachment-0001.html>


More information about the cfe-commits mailing list