diff options
Diffstat (limited to 'Build/source/utils/asymptote/LspCpp/include/LibLsp/JsonRpc/future.h')
-rw-r--r-- | Build/source/utils/asymptote/LspCpp/include/LibLsp/JsonRpc/future.h | 178 |
1 files changed, 178 insertions, 0 deletions
diff --git a/Build/source/utils/asymptote/LspCpp/include/LibLsp/JsonRpc/future.h b/Build/source/utils/asymptote/LspCpp/include/LibLsp/JsonRpc/future.h new file mode 100644 index 00000000000..8e241d96e9b --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/include/LibLsp/JsonRpc/future.h @@ -0,0 +1,178 @@ +// Copyright 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include <condition_variable> +#include <memory> +#include <mutex> + +namespace lsp { + +// internal functionality +namespace detail { +template <typename T> +struct promise_state { + T val; + std::mutex mutex; + std::condition_variable cv; + bool hasVal = false; +}; +} // namespace detail + +// forward declaration +template <typename T> +class promise; + +// future_status is the enumeration returned by future::wait_for and +// future::wait_until. +enum class future_status { + ready, + timeout, +}; + +// future is a minimal reimplementation of std::future, that does not suffer +// from TSAN false positives. See: +// https://gcc.gnu.org/bugzilla//show_bug.cgi?id=69204 +template <typename T> +class future { + public: + using State = detail::promise_state<T>; + + // constructors + inline future() = default; + inline future(future&&) = default; + + // valid() returns true if the future has an internal state. + bool valid() const; + + // get() blocks until the future has a valid result, and returns it. + // The future must have a valid internal state to call this method. + inline T get(); + + // wait() blocks until the future has a valid result. + // The future must have a valid internal state to call this method. + void wait() const; + + // wait_for() blocks until the future has a valid result, or the timeout is + // reached. + // The future must have a valid internal state to call this method. + template <class Rep, class Period> + future_status wait_for( + const std::chrono::duration<Rep, Period>& timeout) const; + + // wait_until() blocks until the future has a valid result, or the timeout is + // reached. + // The future must have a valid internal state to call this method. + template <class Clock, class Duration> + future_status wait_until( + const std::chrono::time_point<Clock, Duration>& timeout) const; + + private: + friend promise<T>; + future(const future&) = delete; + inline future(const std::shared_ptr<State>& state); + + std::shared_ptr<State> state = std::make_shared<State>(); +}; + +template <typename T> +future<T>::future(const std::shared_ptr<State>& s) : state(s) {} + +template <typename T> +bool future<T>::valid() const { + return static_cast<bool>(state); +} + +template <typename T> +T future<T>::get() { + std::unique_lock<std::mutex> lock(state->mutex); + state->cv.wait(lock, [&] { return state->hasVal; }); + return state->val; +} + +template <typename T> +void future<T>::wait() const { + std::unique_lock<std::mutex> lock(state->mutex); + state->cv.wait(lock, [&] { return state->hasVal; }); +} + +template <typename T> +template <class Rep, class Period> +future_status future<T>::wait_for( + const std::chrono::duration<Rep, Period>& timeout) const { + std::unique_lock<std::mutex> lock(state->mutex); + return state->cv.wait_for(lock, timeout, [&] { return state->hasVal; }) + ? future_status::ready + : future_status::timeout; +} + +template <typename T> +template <class Clock, class Duration> +future_status future<T>::wait_until( + const std::chrono::time_point<Clock, Duration>& timeout) const { + std::unique_lock<std::mutex> lock(state->mutex); + return state->cv.wait_until(lock, timeout, [&] { return state->hasVal; }) + ? future_status::ready + : future_status::timeout; +} + +// promise is a minimal reimplementation of std::promise, that does not suffer +// from TSAN false positives. See: +// https://gcc.gnu.org/bugzilla//show_bug.cgi?id=69204 +template <typename T> +class promise { + public: + // constructors + inline promise() = default; + inline promise(promise&& other) = default; + inline promise(const promise& other) = default; + + // set_value() stores value to the shared state. + // set_value() must only be called once. + inline void set_value(const T& value) const; + inline void set_value(T&& value) const; + + // get_future() returns a future sharing this promise's state. + future<T> get_future(); + + private: + using State = detail::promise_state<T>; + std::shared_ptr<State> state = std::make_shared<State>(); +}; + +template <typename T> +future<T> promise<T>::get_future() { + return future<T>(state); +} + +template <typename T> +void promise<T>::set_value(const T& value) const { + std::unique_lock<std::mutex> lock(state->mutex); + state->val = value; + state->hasVal = true; + state->cv.notify_all(); +} + +template <typename T> +void promise<T>::set_value(T&& value) const { + std::unique_lock<std::mutex> lock(state->mutex); + state->val = std::move(value); + state->hasVal = true; + state->cv.notify_all(); +} + +} // namespace lsp + + |