/** * Tencent is pleased to support the open source community by making Tars available. * * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause * * 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. */ #ifndef _TARS_PROMISE_H_ #define _TARS_PROMISE_H_ #include #include #include #include #include "promise/template_helper.h" #include "promise/exception.h" #include "promise/bind.h" namespace tars { // pre-declare future type. template class Future; template struct IsFutureType : std::false_type {}; // only Future is a future type. template struct IsFutureType > : std::true_type {}; // pre-declare promise type. template class Promise; namespace promise { template struct UnderlyType { using Type = T; }; template struct UnderlyType > { using Type = T; }; template struct FutureTypeTraits { using StorageType = std::shared_ptr; using RValueType = const T&; using LValueType = const T&; using DestType = T&; static void init(StorageType& s, RValueType v) { s.reset(new T(v)); } static void assign(DestType d, const StorageType& s) { d = *s; } }; // since value maybe set in the future, there is no need to check type [const T&] template struct FutureTypeTraits { using StorageType = T*; using RValueType = T&; using LValueType = T&; using DestType = T*&; static void init(StorageType& s, RValueType v) { s = &v; } static void assign(DestType d, const StorageType& s) { d = s; } }; // void type. template <> struct FutureTypeTraits { using RValueType = void; using LValueType = void; }; template class FutureInterface { public: using RValueType = typename FutureTypeTraits::RValueType; using LValueType = typename FutureTypeTraits::LValueType; using DestType = typename FutureTypeTraits::DestType; using FutureType = std::shared_ptr >; using Watcher = Callback; virtual ~FutureInterface() {} virtual bool isDone() const = 0; virtual bool hasValue() const = 0; virtual bool hasException() const = 0; virtual LValueType get() const = 0; virtual bool tryGet(DestType d) const = 0; virtual void setValue(RValueType v) = 0; virtual void setException(ExceptionPtr exp) = 0; virtual void appendWacther(const Watcher& watcher) = 0; protected: FutureInterface() {} }; template <> class FutureInterface { public: using RValueType = typename FutureTypeTraits::RValueType; using LValueType = typename FutureTypeTraits::LValueType; using FutureType = std::shared_ptr >; using Watcher = Callback; virtual ~FutureInterface() {} virtual bool isDone() const = 0; virtual bool hasValue() const = 0; virtual bool hasException() const = 0; virtual LValueType get() const = 0; virtual void set() = 0; virtual void setException(ExceptionPtr exp) = 0; virtual void appendWacther(const Watcher& watcher) = 0; protected: FutureInterface() {} }; template class PromptFutureImpl final : public FutureInterface , public std::enable_shared_from_this > { public: using RValueType = typename FutureInterface::RValueType; using LValueType = typename FutureInterface::LValueType; using DestType = typename FutureInterface::DestType; using Watcher = typename FutureInterface::Watcher; PromptFutureImpl(RValueType v) : m_value() , m_exp() { FutureTypeTraits::init(m_value, v); } PromptFutureImpl(ExceptionPtr exp) : m_value() , m_exp(exp) { } bool isDone() const override { return true; } bool hasValue() const override { if (m_exp) return false; return true; } bool hasException() const override { return (!!m_exp); } LValueType get() const override { if (m_exp) m_exp->rethrow(); return *m_value; } bool tryGet(DestType d) const override { if (m_exp) m_exp->rethrow(); FutureTypeTraits::assign(d, m_value); return true; } void setValue(RValueType v) override { // do not touch this. } void setException(ExceptionPtr exp) override { // do not touch this. } void appendWacther(const Watcher& watcher) override { try { if (watcher) watcher.run(this->shared_from_this()); } catch (...) { } } private: typename FutureTypeTraits::StorageType m_value; ExceptionPtr m_exp; }; template <> class PromptFutureImpl final : public FutureInterface , public std::enable_shared_from_this > { public: using RValueType = typename FutureInterface::RValueType; using LValueType = typename FutureInterface::LValueType; using Watcher = typename FutureInterface::Watcher; PromptFutureImpl() : m_exp() { } PromptFutureImpl(ExceptionPtr exp) : m_exp(exp) { } bool isDone() const override { return true; } bool hasValue() const override { if (m_exp) return false; return true; } bool hasException() const override { return (!!m_exp); } LValueType get() const override { if (m_exp) m_exp->rethrow(); } void set() override { // do not touch this. } void setException(ExceptionPtr exp) override { // do not touch this. } void appendWacther(const Watcher& watcher) override { try { if (watcher) watcher.run(this->shared_from_this()); } catch (...) { } } private: ExceptionPtr m_exp; }; class FutureInternal { public: virtual ~FutureInternal() {} bool isDone() const { std::lock_guard lock(m_mutex); return m_isDone; } bool hasValue() const { std::lock_guard lock(m_mutex); return m_isDone && !m_exp; } bool hasException() const { std::lock_guard lock(m_mutex); return m_isDone && m_exp; } void markFinishWithException(const ExceptionPtr& exp) { { std::lock_guard lock(m_mutex); if (m_isDone) throw Exception("Duplicated mark finish with exception."); m_isDone = true; m_exp = exp; } m_cv.notify_all(); } void wait() const { { std::unique_lock lock(m_mutex); m_cv.wait(lock, [&]{ return m_isDone; }); } if (m_exp) m_exp->rethrow(); } protected: FutureInternal() : m_mutex() , m_cv() , m_isDone(false) , m_exp() { } mutable std::mutex m_mutex; mutable std::condition_variable m_cv; bool m_isDone; ExceptionPtr m_exp; }; template class FutureImpl : public FutureInterface , public std::enable_shared_from_this > , private FutureInternal { public: using RValueType = typename FutureInterface::RValueType; using LValueType = typename FutureInterface::LValueType; using DestType = typename FutureInterface::DestType; using Watcher = typename FutureInterface::Watcher; FutureImpl() : m_value() , m_watchers() { } bool isDone() const override { return FutureInternal::isDone(); } bool hasValue() const override { return FutureInternal::hasValue(); } bool hasException() const override { return FutureInternal::hasException(); } LValueType get() const override { wait(); return *m_value; } bool tryGet(DestType d) const override { if (!FutureInternal::isDone()) return false; if (m_exp) m_exp->rethrow(); FutureTypeTraits::assign(d, m_value); return true; } void setValue(RValueType v) override { { // FixMe: move this to FutureInternal. std::lock_guard lock(m_mutex); if (m_isDone) throw Exception("Duplicated set value."); m_isDone = true; FutureTypeTraits::init(m_value, v); } m_cv.notify_all(); invokeWatchers(); } void setException(ExceptionPtr exp) override { markFinishWithException(exp); invokeWatchers(); } void appendWacther(const Watcher& watcher) override { if (!watcher) return; if (FutureInternal::isDone()) { try { if (watcher) watcher.run(this->shared_from_this()); } catch (...) { } } else { std::lock_guard lock(m_mutex); m_watchers.push_back(watcher); } } protected: void invokeWatchers() { std::vector watchers; { std::lock_guard lock(m_mutex); watchers.swap(m_watchers); } for (const Watcher& w : watchers) { try { w.run(this->shared_from_this()); } catch (...) { } } } typename FutureTypeTraits::StorageType m_value; std::vector m_watchers; }; template <> class FutureImpl : public FutureInterface , public std::enable_shared_from_this > , private FutureInternal { public: using RValueType = typename FutureInterface::RValueType; using LValueType = typename FutureInterface::LValueType; using Watcher = typename FutureInterface::Watcher; FutureImpl() : m_watchers() { } bool isDone() const override { return FutureInternal::isDone(); } bool hasValue() const override { return FutureInternal::hasValue(); } bool hasException() const override { return FutureInternal::hasException(); } LValueType get() const override { wait(); } void set() override { { // FixMe: move this to FutureInternal. std::lock_guard lock(m_mutex); if (m_isDone) throw Exception("Duplicated set finish."); m_isDone = true; } m_cv.notify_all(); invokeWatchers(); } void setException(ExceptionPtr exp) override { markFinishWithException(exp); invokeWatchers(); } void appendWacther(const Watcher& watcher) override { if (!watcher) return; if (FutureInternal::isDone()) { try { if (watcher) watcher.run(this->shared_from_this()); } catch (...) { } } else { std::lock_guard lock(m_mutex); m_watchers.push_back(watcher); } } protected: void invokeWatchers() { std::vector watchers; { std::lock_guard lock(m_mutex); watchers.swap(m_watchers); } for (const Watcher& w : watchers) { try { w.run(this->shared_from_this()); } catch (...) { } } } std::vector m_watchers; }; // support sequential watchers. template class ForwardWatcher; template class SequentialWatcher { using ValueType = typename UnderlyType::Type; using FuturePtr = std::shared_ptr >; using Watcher = Callback&)>; public: SequentialWatcher(const Watcher& w, const Promise& p) : m_watcher(w) , m_promise(p) { } template enable_if_t::value> invoke(const FuturePtr& future) { try { m_watcher.run(future); m_promise.set(); } catch (...) { m_promise.setException(currentException()); } } template enable_if_t::value && !IsFutureType::value> invoke(const FuturePtr& future) { try { m_promise.setValue(m_watcher.run(future)); } catch (...) { m_promise.setException(currentException()); } } template enable_if_t::value> invoke(const FuturePtr& future) { try { // sequential watcher. m_watcher.run(future).then(Bind(&ForwardWatcher::template invoke, std::make_shared >(m_promise))); } catch (...) { m_promise.setException(currentException()); } } protected: Watcher m_watcher; Promise m_promise; }; template class ForwardWatcher { public: ForwardWatcher(const Promise& p) : m_promise(p) { } template enable_if_t::value> invoke(const Future& future) { try { future.get(); m_promise.set(); } catch (...) { m_promise.setException(currentException()); } } template enable_if_t::value> invoke(const Future& future) { try { m_promise.setValue(future.get()); } catch (...) { m_promise.setException(currentException()); } } protected: Promise m_promise; }; template class FutureBase { public: using LValueType = typename FutureTypeTraits::LValueType; FutureBase() : m_future() { } FutureBase(ExceptionPtr exp) : m_future(new PromptFutureImpl(exp)) { } virtual ~FutureBase() {} LValueType get() const { if (!m_future) throw Exception("future uninitialized"); return m_future->get(); } bool isDone() const { if (!m_future) return false; return m_future->isDone(); } bool hasValue() const { if (!m_future) return false; return m_future->hasValue(); } bool hasException() const { if (!m_future) return false; return m_future->hasException(); } // safe bool idiom // refer: https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Safe_bool // c++11 standard explicit operator bool() const { return m_future ? true : false; } protected: using FuturePtr = std::shared_ptr >; FutureBase(const FuturePtr& future) : m_future(future) { } FuturePtr m_future; }; } // end namespace promise template class Future : public promise::FutureBase { public: explicit Future(typename promise::FutureTypeTraits::RValueType v) : promise::FutureBase(new promise::PromptFutureImpl(v)) { } Future(ExceptionPtr exp) : promise::FutureBase(exp) { } // can be initialize in tuple. Future() = default; ~Future() override {} template Future::Type> then(const Callback&)>& watcher) { using ValueType = typename promise::UnderlyType::Type; if (!this->m_future) throw Exception("future uninitialized"); Promise promise; this->m_future->appendWacther(Bind(&promise::SequentialWatcher::template invoke, std::make_shared >(watcher, promise))); return promise.getFuture(); } private: using FuturePtr = typename promise::FutureBase::FuturePtr; Future(const FuturePtr& future) : promise::FutureBase(future) { } template friend class promise::SequentialWatcher; friend class Promise; }; template <> class Future : public promise::FutureBase { public: // can be initialize in tuple. Future() = default; Future(ExceptionPtr exp) : promise::FutureBase(exp) { } ~Future() override {} template Future::Type> then(const Callback&)>& watcher) { using ValueType = typename promise::UnderlyType::Type; if (!this->m_future) throw Exception("future uninitialized"); Promise promise; this->m_future->appendWacther(Bind(&promise::SequentialWatcher::template invoke, std::make_shared >(watcher, promise))); return promise.getFuture(); } private: using FuturePtr = typename promise::FutureBase::FuturePtr; Future(const FuturePtr& future) : promise::FutureBase(future) { } template friend class promise::SequentialWatcher; friend class Promise; }; template class Promise final { public: using ValueType = typename promise::UnderlyType::Type; Promise() : m_future(new promise::FutureImpl()) { } void setValue(typename promise::FutureTypeTraits::RValueType v) { m_future->setValue(v); } void setException(const ExceptionPtr& e) { m_future->setException(e); } Future getFuture() { return m_future; } private: std::shared_ptr > m_future; }; template <> class Promise final { public: Promise() : m_future(new promise::FutureImpl()) { } void set() { m_future->set(); } void setException(const ExceptionPtr& e) { m_future->setException(e); } Future getFuture() { return m_future; } private: std::shared_ptr > m_future; }; } // end namespace tars #endif