diff --git a/include/pistache/async.h b/include/pistache/async.h index 038ad13cd68006265487ce9cb3137942fa4d2670..bf3524ccc0281b9ec0aa9ab1278591bacae15569 100644 --- a/include/pistache/async.h +++ b/include/pistache/async.h @@ -9,1595 +9,1372 @@ #include <pistache/typeid.h> -#include <type_traits> +#include <atomic> +#include <condition_variable> #include <functional> #include <memory> -#include <atomic> -#include <vector> #include <mutex> -#include <condition_variable> #include <stdexcept> +#include <type_traits> #include <typeinfo> - +#include <vector> namespace Pistache { namespace Async { - class Error : public std::runtime_error { - public: - explicit Error(const char* what) : std::runtime_error(what) { } - explicit Error(const std::string& what) : std::runtime_error(what) { } - }; +class Error : public std::runtime_error { +public: + explicit Error(const char *what) : std::runtime_error(what) {} + explicit Error(const std::string &what) : std::runtime_error(what) {} +}; - class BadType : public Error { - public: - explicit BadType(TypeId id) - : Error("Argument type can not be used to resolve the promise " - " (TypeId does not match)") - , id_(std::move(id)) - { } +class BadType : public Error { +public: + explicit BadType(TypeId id) + : Error("Argument type can not be used to resolve the promise " + " (TypeId does not match)"), + id_(std::move(id)) {} - TypeId typeId() const { - return id_; - } + TypeId typeId() const { return id_; } - private: - TypeId id_; - }; +private: + TypeId id_; +}; - class BadAnyCast : public std::bad_cast { - public: - const char* what() const noexcept override { return "Bad any cast"; } - virtual ~BadAnyCast() { } - }; +class BadAnyCast : public std::bad_cast { +public: + const char *what() const noexcept override { return "Bad any cast"; } + virtual ~BadAnyCast() {} +}; - enum class State { - Pending, Fulfilled, Rejected - }; +enum class State { Pending, Fulfilled, Rejected }; - template<typename T> class Promise; +template <typename T> class Promise; - class PromiseBase { - public: - virtual ~PromiseBase() { } - virtual bool isPending() const = 0; - virtual bool isFulfilled() const = 0; - virtual bool isRejected() const = 0; +class PromiseBase { +public: + virtual ~PromiseBase() {} + virtual bool isPending() const = 0; + virtual bool isFulfilled() const = 0; + virtual bool isRejected() const = 0; - bool isSettled() const { return isFulfilled() || isRejected(); } - }; + bool isSettled() const { return isFulfilled() || isRejected(); } +}; - namespace detail { - template<typename Func, typename T> - struct IsCallable { +namespace detail { +template <typename Func, typename T> struct IsCallable { - template<typename U> - static auto test(U *) -> decltype(std::declval<Func>()(std::declval<U>()), std::true_type()); + template <typename U> + static auto test(U *) + -> decltype(std::declval<Func>()(std::declval<U>()), std::true_type()); - template<typename U> - static auto test(...) -> std::false_type; + template <typename U> static auto test(...) -> std::false_type; - static constexpr bool value = std::is_same<decltype(test<T>(0)), std::true_type>::value; - }; + static constexpr bool value = + std::is_same<decltype(test<T>(0)), std::true_type>::value; +}; - template<typename Func> - struct IsMoveCallable : public IsMoveCallable<decltype(&Func::operator())> { }; +template <typename Func> +struct IsMoveCallable : public IsMoveCallable<decltype(&Func::operator())> {}; - template<typename R, typename Class, typename Arg> - struct IsMoveCallable<R (Class::*)(Arg) const> : public std::is_rvalue_reference<Arg> { }; +template <typename R, typename Class, typename Arg> +struct IsMoveCallable<R (Class::*)(Arg) const> + : public std::is_rvalue_reference<Arg> {}; - template<typename Func, typename Arg> - typename std::conditional< - IsMoveCallable<Func>::value, - Arg&&, - const Arg& - >::type tryMove(Arg& arg) { - return std::move(arg); - } +template <typename Func, typename Arg> +typename std::conditional<IsMoveCallable<Func>::value, Arg &&, + const Arg &>::type +tryMove(Arg &arg) { + return std::move(arg); +} + +template <typename Func> +struct FunctionTrait : public FunctionTrait<decltype(&Func::operator())> {}; + +template <typename R, typename Class, typename... Args> +struct FunctionTrait<R (Class::*)(Args...) const> { + typedef R ReturnType; + + static constexpr size_t ArgsCount = sizeof...(Args); +}; + +template <typename R, typename Class, typename... Args> +struct FunctionTrait<R (Class::*)(Args...)> { + typedef R ReturnType; + + static constexpr size_t ArgsCount = sizeof...(Args); +}; + +template <typename T> struct RemovePromise { typedef T Type; }; + +template <typename T> struct RemovePromise<Promise<T>> { typedef T Type; }; + +template <size_t N, typename... T> struct nth_element; + +template <typename Head, typename... Tail> +struct nth_element<0, Head, Tail...> { + typedef Head type; +}; - template<typename Func> - struct FunctionTrait : public FunctionTrait<decltype(&Func::operator())> { }; +template <size_t N, typename Head, typename... Tail> +struct nth_element<N, Head, Tail...> { + typedef typename nth_element<N - 1, Tail...>::type type; +}; - template<typename R, typename Class, typename... Args> - struct FunctionTrait<R (Class::*)(Args...) const> { - typedef R ReturnType; +} // namespace detail - static constexpr size_t ArgsCount = sizeof...(Args); - }; +namespace Private { - template<typename R, typename Class, typename... Args> - struct FunctionTrait<R (Class::*)(Args...)> { - typedef R ReturnType; +struct InternalRethrow { + explicit InternalRethrow(std::exception_ptr _exc) : exc(std::move(_exc)) {} - static constexpr size_t ArgsCount = sizeof...(Args); - }; + std::exception_ptr exc; +}; - template<typename T> - struct RemovePromise { - typedef T Type; - }; +struct IgnoreException { + void operator()(std::exception_ptr) const {} +}; - template<typename T> - struct RemovePromise<Promise<T>> { - typedef T Type; - }; +struct NoExcept { + void operator()(std::exception_ptr) const { std::terminate(); } +}; - template<size_t N, typename... T> struct nth_element; +struct Throw { + void operator()(std::exception_ptr exc) const { + throw InternalRethrow(std::move(exc)); + } +}; - template<typename Head, typename... Tail> - struct nth_element<0, Head, Tail...> { - typedef Head type; - }; +struct Core; - template<size_t N, typename Head, typename... Tail> - struct nth_element<N, Head, Tail...> { - typedef typename nth_element<N - 1, Tail...>::type type; - }; +class Request { +public: + virtual void resolve(const std::shared_ptr<Core> &core) = 0; + virtual void reject(const std::shared_ptr<Core> &core) = 0; + virtual ~Request() {} +}; +struct Core { + Core(State _state, TypeId _id) + : allocated(false), state(_state), exc(), mtx(), requests(), id(_id) {} + + bool allocated; + std::atomic<State> state; + std::exception_ptr exc; + + /* + * We need this lock because a Promise might be resolved or rejected from a + * thread A while a continuation to the same Promise (Core) might be attached + * at the same from a thread B. If that's the case, then we need to serialize + * operations so that we avoid a race-condition. + * + * Since we have a lock, we have a blocking progress guarantee but I don't + * expect this to be a major bottleneck as I don't expect major contention on + * the lock If it ends up being a bottlenick, try @improving it by + * experimenting with a lock-free scheme + */ + std::mutex mtx; + std::vector<std::shared_ptr<Request>> requests; + TypeId id; + + virtual void *memory() = 0; + + virtual bool isVoid() const = 0; + + template <typename T, typename... Args> void construct(Args &&... args) { + if (isVoid()) + throw Error("Can not construct a void core"); + + if (id != TypeId::of<T>()) { + throw BadType(id); } - namespace Private { - - struct InternalRethrow { - explicit InternalRethrow(std::exception_ptr _exc) - : exc(std::move(_exc)) - { } - - std::exception_ptr exc; - }; - - struct IgnoreException { - void operator()(std::exception_ptr) const { } - }; - - struct NoExcept { - void operator()(std::exception_ptr) const { std::terminate(); } - }; - - struct Throw { - void operator()(std::exception_ptr exc) const { - throw InternalRethrow(std::move(exc)); - } - }; - - struct Core; - - class Request { - public: - virtual void resolve(const std::shared_ptr<Core>& core) = 0; - virtual void reject(const std::shared_ptr<Core>& core) = 0; - virtual ~Request() {} - }; - - struct Core { - Core(State _state, TypeId _id) - : allocated(false) - , state(_state) - , exc() - , mtx() - , requests() - , id(_id) - { } - - bool allocated; - std::atomic<State> state; - std::exception_ptr exc; - - /* - * We need this lock because a Promise might be resolved or rejected from a thread A - * while a continuation to the same Promise (Core) might be attached at the same from - * a thread B. If that's the case, then we need to serialize operations so that we - * avoid a race-condition. - * - * Since we have a lock, we have a blocking progress guarantee but I don't expect this - * to be a major bottleneck as I don't expect major contention on the lock - * If it ends up being a bottlenick, try @improving it by experimenting with a lock-free - * scheme - */ - std::mutex mtx; - std::vector<std::shared_ptr<Request>> requests; - TypeId id; - - virtual void* memory() = 0; - - virtual bool isVoid() const = 0; - - template<typename T, typename... Args> - void construct(Args&&... args) { - if (isVoid()) - throw Error("Can not construct a void core"); - - if (id != TypeId::of<T>()) { - throw BadType(id); - } - - void *mem = memory(); - - if (allocated) { - reinterpret_cast<T*>(mem)->~T(); - allocated = false; - } - - new (mem) T(std::forward<Args>(args)...); - allocated = true; - state = State::Fulfilled; - } - - virtual ~Core() {} - }; - - template<typename T> - struct CoreT : public Core { - CoreT() - : Core(State::Pending, TypeId::of<T>()) - , storage() - { } - - ~CoreT() { - if (allocated) { - reinterpret_cast<T*>(&storage)->~T(); - allocated = false; - } - } - - template<class Other> - struct Rebind { - typedef CoreT<Other> Type; - }; - - T& value() { - if (state != State::Fulfilled) - throw Error("Attempted to take the value of a not fulfilled promise"); - - return *reinterpret_cast<T*>(&storage); - } - - bool isVoid() const override { return false; } - - protected: - void *memory() override { - return &storage; - } - - private: - typedef typename std::aligned_storage<sizeof(T), alignof(T)>::type Storage; - Storage storage; - }; - - template<> - struct CoreT<void> : public Core { - CoreT() - : Core(State::Pending, TypeId::of<void>()) - { } - - bool isVoid() const override { return true; } - - protected: - void *memory() override { - return nullptr; - } - }; - - template<typename T> - struct Continuable : public Request { - explicit Continuable(const std::shared_ptr<Core>& chain) - : resolveCount_(0) - , rejectCount_(0) - , chain_(chain) - { } - - void resolve(const std::shared_ptr<Core>& core) override { - if (resolveCount_ >= 1) - return; //TODO is this the right thing? - //throw Error("Resolve must not be called more than once"); - - ++resolveCount_; - doResolve(coreCast(core)); - } - - void reject(const std::shared_ptr<Core>& core) override { - if (rejectCount_ >= 1) - return; //TODO is this the right thing? - //throw Error("Reject must not be called more than once"); - - ++rejectCount_; - try { - doReject(coreCast(core)); - } catch (const InternalRethrow& e) { - chain_->exc = std::move(e.exc); - chain_->state = State::Rejected; - for (const auto& req: chain_->requests) { - req->reject(chain_); - } - } - - } - - std::shared_ptr<CoreT<T>> coreCast(const std::shared_ptr<Core>& core) const { - return std::static_pointer_cast<CoreT<T>>(core); - } - - virtual void doResolve(const std::shared_ptr<CoreT<T>>& core) = 0; - virtual void doReject(const std::shared_ptr<CoreT<T>>& core) = 0; - - virtual ~Continuable() { } - - size_t resolveCount_; - size_t rejectCount_; - std::shared_ptr<Core> chain_; - }; - - namespace impl { - - template<typename T, typename Resolve, typename Reject, typename U> struct Continuation; - - template<typename T, typename Resolve, typename Reject, typename Res, typename Cls, typename... Args> - struct Continuation<T, Resolve, Reject, Res (Cls::*)(Args...) const> : public Continuation<T, Resolve, Reject, Res (Args...)> { - typedef Continuation<T, Resolve, Reject, Res (Args...)> Base; - - Continuation( - const std::shared_ptr<Core>& chain, - Resolve resolve, - Reject reject) - : Base(chain, std::move(resolve), std::move(reject)) - { } - }; - - template<typename T, typename Resolve, typename Reject, typename Res, typename Cls, typename... Args> - struct Continuation<T, Resolve, Reject, Res (Cls::*)(Args...)> : public Continuation<T, Resolve, Reject, Res (Args...)> { - typedef Continuation<T, Resolve, Reject, Res (Args...)> Base; - - Continuation( - const std::shared_ptr<Core>& chain, - Resolve resolve, - Reject reject) - : Base(chain, std::move(resolve), std::move(reject)) - { } - }; - - // General specialization - template<typename T, typename Resolve, typename Reject, typename Res, typename... Args> - struct Continuation<T, Resolve, Reject, Res (Args...)> : public Continuable<T> { - - static_assert(sizeof...(Args) == 1, - "A continuation should only take one single argument"); - - typedef typename detail::nth_element<0, Args...>::type Arg; - - static_assert( - std::is_same<T, Arg>::value || - std::is_convertible<T, Arg>::value, - "Incompatible types detected"); - - Continuation( - const std::shared_ptr<Core>& chain, - Resolve resolve, - Reject reject) - : Continuable<T>(chain) - , resolve_(resolve) - , reject_(reject) - { } - - void doResolve(const std::shared_ptr<CoreT<T>>& core) override { - finishResolve(resolve_(detail::tryMove<Resolve>(core->value()))); - } - - void doReject(const std::shared_ptr<CoreT<T>>& core) override { - reject_(core->exc); - for (const auto& req: this->chain_->requests) { - req->reject(this->chain_); - } - } - - template<typename Ret> - void finishResolve(Ret&& ret) const { - typedef typename std::decay<Ret>::type CleanRet; - this->chain_->template construct<CleanRet>(std::forward<Ret>(ret)); - for (const auto& req: this->chain_->requests) { - req->resolve(this->chain_); - } - } - - Resolve resolve_; - Reject reject_; - }; - - // Specialization for a void-Promise - template<typename Resolve, typename Reject, typename Res, typename... Args> - struct Continuation<void, Resolve, Reject, Res (Args...)> : public Continuable<void> { - - Continuation( - const std::shared_ptr<Core>& chain, - Resolve resolve, - Reject reject) - : Continuable<void>(chain) - , resolve_(resolve) - , reject_(reject) - { } - - static_assert(sizeof...(Args) == 0, - "Can not attach a non-void continuation to a void-Promise"); - - void doResolve(const std::shared_ptr<CoreT<void>>& /*core*/) { - finishResolve(resolve_()); - } - - void doReject(const std::shared_ptr<CoreT<void>>& core) { - reject_(core->exc); - for (const auto& req: this->chain_->requests) { - req->reject(this->chain_); - } - } - - template<typename Ret> - void finishResolve(Ret&& ret) const { - typedef typename std::remove_reference<Ret>::type CleanRet; - this->chain_->template construct<CleanRet>(std::forward<Ret>(ret)); - for (const auto& req: this->chain_->requests) { - req->resolve(this->chain_); - } - } - - Resolve resolve_; - Reject reject_; - }; - - // Specialization for a callback returning void - template<typename T, typename Resolve, typename Reject, typename... Args> - struct Continuation<T, Resolve, Reject, void (Args...)> : public Continuable<T> { - - Continuation( - const std::shared_ptr<Core>& chain, - Resolve resolve, - Reject reject) - : Continuable<T>(chain) - , resolve_(resolve) - , reject_(reject) - { } - - static_assert(sizeof...(Args) == 1, - "A continuation should only take one single argument"); - - typedef typename detail::nth_element<0, Args...>::type Arg; - - static_assert( - std::is_same<T, Arg>::value || - std::is_convertible<T, Arg>::value, - "Incompatible types detected"); - - - void doResolve(const std::shared_ptr<CoreT<T>>& core) override { - resolve_(core->value()); - } - - void doReject(const std::shared_ptr<CoreT<T>>& core) override { - reject_(core->exc); - } - - Resolve resolve_; - Reject reject_; - }; - - - // Specialization for a void-Promise on a callback returning void - template<typename Resolve, typename Reject, typename... Args> - struct Continuation<void, Resolve, Reject, void (Args...)> : public Continuable<void> { - - Continuation( - const std::shared_ptr<Core>& chain, - Resolve resolve, - Reject reject) - : Continuable<void>(chain) - , resolve_(resolve) - , reject_(reject) - { } - - static_assert(sizeof...(Args) == 0, - "Can not attach a non-void continuation to a void-Promise"); - - void doResolve(const std::shared_ptr<CoreT<void>>& /*core*/) override { - resolve_(); - } - - void doReject(const std::shared_ptr<CoreT<void>>& core) override { - reject_(core->exc); - } - - Resolve resolve_; - Reject reject_; - - }; - - // Specialization for a callback returning a Promise - template<typename T, typename Resolve, typename Reject, typename U, typename... Args> - struct Continuation<T, Resolve, Reject, Promise<U> (Args...)> : public Continuable<T> { - - static_assert(sizeof...(Args) == 1, - "A continuation should only take one single argument"); - - typedef typename detail::nth_element<0, Args...>::type Arg; - - static_assert( - std::is_same<T, Arg>::value || - std::is_convertible<T, Arg>::value, - "Incompatible types detected"); - - Continuation( - const std::shared_ptr<Core>& chain, - Resolve resolve, - Reject reject) - : Continuable<T>(chain) - , resolve_(resolve) - , reject_(reject) - { } - - void doResolve(const std::shared_ptr<CoreT<T>>& core) override { - auto promise = resolve_(detail::tryMove<Resolve>(core->value())); - finishResolve(promise); - } - - void doReject(const std::shared_ptr<CoreT<T>>& core) override { - reject_(core->exc); - for (const auto& req: core->requests) { - req->reject(core); - } - } - - template<typename PromiseType> - struct Chainer { - explicit Chainer(const std::shared_ptr<Private::Core>& core) - : chainCore(core) - { } - - void operator()(const PromiseType& val) { - chainCore->construct<PromiseType>(val); - for (const auto& req: chainCore->requests) { - req->resolve(chainCore); - } - } - - std::shared_ptr<Core> chainCore; - }; - - template< - typename Promise, - typename Type = typename detail::RemovePromise<Promise>::Type> - Chainer<Type> - makeChainer(const Promise&) { - return Chainer<Type>(this->chain_); - } - - template<typename P> - void finishResolve(P& promise) { - auto chainer = makeChainer(promise); - std::weak_ptr<Core> weakPtr = this->chain_; - promise.then(std::move(chainer), [weakPtr](std::exception_ptr exc) { - if (auto core = weakPtr.lock()) { - core->exc = std::move(exc); - core->state = State::Rejected; - - for (const auto& req: core->requests) { - req->reject(core); - } - } - }); - - } - - Resolve resolve_; - Reject reject_; - - }; - - // Specialization for a void callback returning a Promise - template<typename Resolve, typename Reject, typename U, typename... Args> - struct Continuation<void, Resolve, Reject, Promise<U> (Args...)> : public Continuable<void> { - - static_assert(sizeof...(Args) == 0, - "Can not attach a non-void continuation to a void-Promise"); - - Continuation( - const std::shared_ptr<Core>& chain, - Resolve resolve, - Reject reject) - : Continuable<void>(chain) - , resolve_(resolve) - , reject_(reject) - { } - - void doResolve(const std::shared_ptr<CoreT<void>>& /*core*/) { - auto promise = resolve_(); - finishResolve(promise); - } - - void doReject(const std::shared_ptr<CoreT<void>>& core) { - reject_(core->exc); - for (const auto& req: core->requests) { - req->reject(core); - } - } - - template<typename PromiseType, typename Dummy = void> - struct Chainer { - explicit Chainer(const std::shared_ptr<Private::Core>& core) - : chainCore(core) - { } - - void operator()(const PromiseType& val) { - chainCore->construct<PromiseType>(val); - for (const auto& req: chainCore->requests) { - req->resolve(chainCore); - } - } - - std::shared_ptr<Core> chainCore; - }; - - template<typename Dummy> - struct Chainer<void, Dummy> { - explicit Chainer(const std::shared_ptr<Private::Core>& core) - : chainCore(core) - { } - - void operator()() { - auto core = this->chain_; - core->state = State::Fulfilled; - - for (const auto& req: chainCore->requests) { - req->resolve(chainCore); - } - } - - std::shared_ptr<Core> chainCore; - }; - - template< - typename Promise, - typename Type = typename detail::RemovePromise<Promise>::Type> - Chainer<Type> - makeChainer(const Promise&) { - return Chainer<Type>(this->chain_); - } - - template<typename P> - void finishResolve(P& promise) { - auto chainer = makeChainer(promise); - promise.then(std::move(chainer), [=](std::exception_ptr exc) { - auto core = this->chain_; - core->exc = std::move(exc); - core->state = State::Rejected; - - for (const auto& req: core->requests) { - req->reject(core); - } - }); - } - - Resolve resolve_; - Reject reject_; - - }; - - } // namespace impl - - template<typename T, typename Resolve, typename Reject, typename Sig> - struct Continuation : public impl::Continuation<T, Resolve, Reject, decltype(&Sig::operator())> - { - - typedef impl::Continuation<T, Resolve, Reject, decltype(&Sig::operator())> Base; - - Continuation( - const std::shared_ptr<Core>& core, - Resolve resolve, - Reject reject) - : Base(core, std::move(resolve), std::move(reject)) - { } - }; - - template<typename T, typename Resolve, typename Reject, typename Res, typename... Args> - struct Continuation<T, Resolve, Reject, Res (*)(Args...)> : public impl::Continuation<T, Resolve, Reject, Res (Args...)> - { - typedef impl::Continuation<T, Resolve, Reject, Res (Args...)> Base; - - Continuation( - const std::shared_ptr<Core>& core, - Resolve resolve, - Reject reject) - : Base(core, std::move(resolve), std::move(reject)) - { } - }; - - template<typename T, typename Resolve, typename Reject, typename Res, typename Cls, typename... Args> - struct Continuation<T, Resolve, Reject, Res (Cls::*)(Args...)> : public impl::Continuation<T, Resolve, Reject, Res (Args...)> - { - typedef impl::Continuation<T, Resolve, Reject, Res (Args...)> Base; - - Continuation( - const std::shared_ptr<Core>& core, - Resolve resolve, - Reject reject) - : Base(core, std::move(resolve), std::move(reject)) - { } - }; - - template<typename T, typename Resolve, typename Reject, typename Res, typename Cls, typename... Args> - struct Continuation<T, Resolve, Reject, Res (Cls::*)(Args...) const> : public impl::Continuation<T, Resolve, Reject, Res (Args...)> - { - typedef impl::Continuation<T, Resolve, Reject, Res (Args...)> Base; - - Continuation( - const std::shared_ptr<Core>& core, - Resolve resolve, - Reject reject) - : Base(core, std::move(resolve), std::move(reject)) - { } - }; - - template<typename T, typename Resolve, typename Reject, typename Res, typename... Args> - struct Continuation<T, Resolve, Reject, std::function<Res (Args...)>> : public impl::Continuation<T, Resolve, Reject, Res (Args...)> { - typedef impl::Continuation<T, Resolve, Reject, Res (Args...)> Base; - - Continuation( - const std::shared_ptr<Core>& core, - Resolve resolve, - Reject reject) - : Base(core, std::move(resolve), std::move(reject)) - { } - }; + void *mem = memory(); + + if (allocated) { + reinterpret_cast<T *>(mem)->~T(); + allocated = false; } - class Resolver { - public: + new (mem) T(std::forward<Args>(args)...); + allocated = true; + state = State::Fulfilled; + } - explicit Resolver(const std::shared_ptr<Private::Core> &core) - : core_(core) - { } + virtual ~Core() {} +}; - Resolver(const Resolver& other) = delete; - Resolver& operator=(const Resolver& other) = delete; +template <typename T> struct CoreT : public Core { + CoreT() : Core(State::Pending, TypeId::of<T>()), storage() {} - Resolver(Resolver&& other) = default; - Resolver& operator=(Resolver&& other) = default; + ~CoreT() { + if (allocated) { + reinterpret_cast<T *>(&storage)->~T(); + allocated = false; + } + } - template<typename Arg> - bool operator()(Arg&& arg) const { - if (!core_) return false; + template <class Other> struct Rebind { typedef CoreT<Other> Type; }; - typedef typename std::remove_reference<Arg>::type Type; + T &value() { + if (state != State::Fulfilled) + throw Error("Attempted to take the value of a not fulfilled promise"); - if (core_->state != State::Pending) - throw Error("Attempt to resolve a fulfilled promise"); + return *reinterpret_cast<T *>(&storage); + } - /* In a ideal world, this should be checked at compile-time rather - * than runtime. However, since types are erased, this looks like - * a difficult task - */ - if (core_->isVoid()) { - throw Error("Attempt to resolve a void promise with arguments"); - } + bool isVoid() const override { return false; } - std::unique_lock<std::mutex> guard(core_->mtx); - core_->construct<Type>(std::forward<Arg>(arg)); +protected: + void *memory() override { return &storage; } - for (const auto& req: core_->requests) { - req->resolve(core_); - } +private: + typedef typename std::aligned_storage<sizeof(T), alignof(T)>::type Storage; + Storage storage; +}; - return true; - } +template <> struct CoreT<void> : public Core { + CoreT() : Core(State::Pending, TypeId::of<void>()) {} - bool operator()() const { - if (!core_) return false; + bool isVoid() const override { return true; } - if (core_->state != State::Pending) - throw Error("Attempt to resolve a fulfilled promise"); +protected: + void *memory() override { return nullptr; } +}; - if (!core_->isVoid()) - throw Error("Attempt ro resolve a non-void promise with no argument"); +template <typename T> struct Continuable : public Request { + explicit Continuable(const std::shared_ptr<Core> &chain) + : resolveCount_(0), rejectCount_(0), chain_(chain) {} - std::unique_lock<std::mutex> guard(core_->mtx); - core_->state = State::Fulfilled; - for (const auto& req: core_->requests) { - req->resolve(core_); - } + void resolve(const std::shared_ptr<Core> &core) override { + if (resolveCount_ >= 1) + return; // TODO is this the right thing? + // throw Error("Resolve must not be called more than once"); - return true; - } + ++resolveCount_; + doResolve(coreCast(core)); + } - void clear() { - core_ = nullptr; - } + void reject(const std::shared_ptr<Core> &core) override { + if (rejectCount_ >= 1) + return; // TODO is this the right thing? + // throw Error("Reject must not be called more than once"); - Resolver clone() { - return Resolver(core_); - } + ++rejectCount_; + try { + doReject(coreCast(core)); + } catch (const InternalRethrow &e) { + chain_->exc = std::move(e.exc); + chain_->state = State::Rejected; + for (const auto &req : chain_->requests) { + req->reject(chain_); + } + } + } - private: - std::shared_ptr<Private::Core> core_; - }; + std::shared_ptr<CoreT<T>> coreCast(const std::shared_ptr<Core> &core) const { + return std::static_pointer_cast<CoreT<T>>(core); + } - class Rejection { - public: + virtual void doResolve(const std::shared_ptr<CoreT<T>> &core) = 0; + virtual void doReject(const std::shared_ptr<CoreT<T>> &core) = 0; - explicit Rejection(const std::shared_ptr<Private::Core>& core) - : core_(core) - { } + virtual ~Continuable() {} - Rejection(const Rejection& other) = delete; - Rejection& operator=(const Rejection& other) = delete; + size_t resolveCount_; + size_t rejectCount_; + std::shared_ptr<Core> chain_; +}; - Rejection(Rejection&& other) = default; - Rejection& operator=(Rejection&& other) = default; +namespace impl { - template<typename Exc> - bool operator()(Exc exc) const { - if (!core_) return false; +template <typename T, typename Resolve, typename Reject, typename U> +struct Continuation; - if (core_->state != State::Pending) - throw Error("Attempt to reject a fulfilled promise"); +template <typename T, typename Resolve, typename Reject, typename Res, + typename Cls, typename... Args> +struct Continuation<T, Resolve, Reject, Res (Cls::*)(Args...) const> + : public Continuation<T, Resolve, Reject, Res(Args...)> { + typedef Continuation<T, Resolve, Reject, Res(Args...)> Base; - std::unique_lock<std::mutex> guard(core_->mtx); - core_->exc = std::make_exception_ptr(exc); - core_->state = State::Rejected; - for (const auto& req: core_->requests) { - req->reject(core_); - } + Continuation(const std::shared_ptr<Core> &chain, Resolve resolve, + Reject reject) + : Base(chain, std::move(resolve), std::move(reject)) {} +}; - return true; - } +template <typename T, typename Resolve, typename Reject, typename Res, + typename Cls, typename... Args> +struct Continuation<T, Resolve, Reject, Res (Cls::*)(Args...)> + : public Continuation<T, Resolve, Reject, Res(Args...)> { + typedef Continuation<T, Resolve, Reject, Res(Args...)> Base; - void clear() { - core_ = nullptr; - } + Continuation(const std::shared_ptr<Core> &chain, Resolve resolve, + Reject reject) + : Base(chain, std::move(resolve), std::move(reject)) {} +}; - Rejection clone() { - return Rejection(core_); - } +// General specialization +template <typename T, typename Resolve, typename Reject, typename Res, + typename... Args> +struct Continuation<T, Resolve, Reject, Res(Args...)> : public Continuable<T> { - private: - std::shared_ptr<Private::Core> core_; + static_assert(sizeof...(Args) == 1, + "A continuation should only take one single argument"); - }; + typedef typename detail::nth_element<0, Args...>::type Arg; - template<typename T> - class Deferred { - public: + static_assert(std::is_same<T, Arg>::value || + std::is_convertible<T, Arg>::value, + "Incompatible types detected"); - Deferred() - : resolver(nullptr) - , rejection(nullptr) - { } + Continuation(const std::shared_ptr<Core> &chain, Resolve resolve, + Reject reject) + : Continuable<T>(chain), resolve_(resolve), reject_(reject) {} - Deferred(const Deferred& other) = delete; - Deferred& operator=(const Deferred& other) = delete; + void doResolve(const std::shared_ptr<CoreT<T>> &core) override { + finishResolve(resolve_(detail::tryMove<Resolve>(core->value()))); + } - Deferred(Deferred&& other) = default; - Deferred& operator=(Deferred&& other) = default; + void doReject(const std::shared_ptr<CoreT<T>> &core) override { + reject_(core->exc); + for (const auto &req : this->chain_->requests) { + req->reject(this->chain_); + } + } - Deferred(Resolver _resolver, Rejection _reject) - : resolver(std::move(_resolver)) - , rejection(std::move(_reject)) - { } + template <typename Ret> void finishResolve(Ret &&ret) const { + typedef typename std::decay<Ret>::type CleanRet; + this->chain_->template construct<CleanRet>(std::forward<Ret>(ret)); + for (const auto &req : this->chain_->requests) { + req->resolve(this->chain_); + } + } - template<typename U> - bool resolve(U&& arg) { - typedef typename std::remove_reference<U>::type CleanU; + Resolve resolve_; + Reject reject_; +}; - static_assert(std::is_same<T, CleanU>::value || std::is_convertible<U, T>::value, - "Types mismatch"); +// Specialization for a void-Promise +template <typename Resolve, typename Reject, typename Res, typename... Args> +struct Continuation<void, Resolve, Reject, Res(Args...)> + : public Continuable<void> { - return resolver(std::forward<U>(arg)); - } + Continuation(const std::shared_ptr<Core> &chain, Resolve resolve, + Reject reject) + : Continuable<void>(chain), resolve_(resolve), reject_(reject) {} - template<typename... Args> - void emplaceResolve(Args&& ...) { - } + static_assert(sizeof...(Args) == 0, + "Can not attach a non-void continuation to a void-Promise"); - template<typename Exc> - bool reject(Exc exc) { - return rejection(std::move(exc)); - } + void doResolve(const std::shared_ptr<CoreT<void>> & /*core*/) { + finishResolve(resolve_()); + } - void clear() { - resolver.clear(); - rejection.clear(); - } + void doReject(const std::shared_ptr<CoreT<void>> &core) { + reject_(core->exc); + for (const auto &req : this->chain_->requests) { + req->reject(this->chain_); + } + } - private: - Resolver resolver; - Rejection rejection; - }; + template <typename Ret> void finishResolve(Ret &&ret) const { + typedef typename std::remove_reference<Ret>::type CleanRet; + this->chain_->template construct<CleanRet>(std::forward<Ret>(ret)); + for (const auto &req : this->chain_->requests) { + req->resolve(this->chain_); + } + } - template<> - class Deferred<void> { - public: + Resolve resolve_; + Reject reject_; +}; - Deferred() - : resolver(nullptr) - , rejection(nullptr) - { } +// Specialization for a callback returning void +template <typename T, typename Resolve, typename Reject, typename... Args> +struct Continuation<T, Resolve, Reject, void(Args...)> : public Continuable<T> { - Deferred(const Deferred& other) = delete; - Deferred& operator=(const Deferred& other) = delete; + Continuation(const std::shared_ptr<Core> &chain, Resolve resolve, + Reject reject) + : Continuable<T>(chain), resolve_(resolve), reject_(reject) {} - Deferred(Deferred&& other) = default; - Deferred& operator=(Deferred&& other) = default; + static_assert(sizeof...(Args) == 1, + "A continuation should only take one single argument"); - Deferred(Resolver _resolver, Rejection _reject) - : resolver(std::move(_resolver)) - , rejection(std::move(_reject)) - { } + typedef typename detail::nth_element<0, Args...>::type Arg; - void resolve() { - resolver(); - } + static_assert(std::is_same<T, Arg>::value || + std::is_convertible<T, Arg>::value, + "Incompatible types detected"); - template<typename Exc> - void reject(Exc _exc) { - rejection(std::move(_exc)); - } + void doResolve(const std::shared_ptr<CoreT<T>> &core) override { + resolve_(core->value()); + } - private: - Resolver resolver; - Rejection rejection; - }; + void doReject(const std::shared_ptr<CoreT<T>> &core) override { + reject_(core->exc); + } - static constexpr Private::IgnoreException IgnoreException{}; - static constexpr Private::NoExcept NoExcept{}; - static constexpr Private::Throw Throw{}; - - namespace details { - - /* - * Note that we could use std::result_of to SFINAE-out and dispatch to the right call - * However, gcc 4.7 does not correctly support std::result_of for SFINAE purposes, so we - * use a decltype SFINAE-expression instead. - * - * See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3462.html and - * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56283 for reference - */ - template<typename T, typename Func> - auto callAsync(Func func, Resolver& resolver, Rejection& rejection) - -> decltype(std::declval<Func>()(resolver, rejection), void()) { - func(resolver, rejection); - } + Resolve resolve_; + Reject reject_; +}; - template<typename T, typename Func> - auto callAsync(Func func, Resolver& resolver, Rejection& rejection) - -> decltype(std::declval<Func>()(Deferred<T>()), void()) { - func(Deferred<T>(std::move(resolver), std::move(rejection))); - } - } - - template<typename T> - class Promise : public PromiseBase - { - public: - template<typename U> friend class Promise; - - typedef Private::CoreT<T> Core; - - template<typename Func> - explicit Promise(Func func) - : core_(std::make_shared<Core>()) - , resolver_(core_) - , rejection_(core_) - { - details::callAsync<T>(func, resolver_, rejection_); - } +// Specialization for a void-Promise on a callback returning void +template <typename Resolve, typename Reject, typename... Args> +struct Continuation<void, Resolve, Reject, void(Args...)> + : public Continuable<void> { - Promise(const Promise<T>& other) = delete; - Promise& operator=(const Promise<T>& other) = delete; + Continuation(const std::shared_ptr<Core> &chain, Resolve resolve, + Reject reject) + : Continuable<void>(chain), resolve_(resolve), reject_(reject) {} - Promise(Promise<T>&& other) = default; - Promise& operator=(Promise<T>&& other) = default; + static_assert(sizeof...(Args) == 0, + "Can not attach a non-void continuation to a void-Promise"); - virtual ~Promise() - { + void doResolve(const std::shared_ptr<CoreT<void>> & /*core*/) override { + resolve_(); + } - } + void doReject(const std::shared_ptr<CoreT<void>> &core) override { + reject_(core->exc); + } - template<typename U> - static - Promise<T> - resolved(U&& value) { - static_assert(!std::is_void<T>::value, - "Can not resolve a void promise with parameters"); - static_assert(std::is_same<T, U>::value || std::is_convertible<U, T>::value, - "Incompatible value type"); - - auto core = std::make_shared<Core>(); - core->template construct<T>(std::forward<U>(value)); - return Promise<T>(std::move(core)); - } + Resolve resolve_; + Reject reject_; +}; - static - Promise<void> - resolved() { - static_assert(std::is_void<T>::value, - "Resolving a non-void promise requires parameters"); +// Specialization for a callback returning a Promise +template <typename T, typename Resolve, typename Reject, typename U, + typename... Args> +struct Continuation<T, Resolve, Reject, Promise<U>(Args...)> + : public Continuable<T> { - auto core = std::make_shared<Core>(); - core->state = State::Fulfilled; - return Promise<T>(std::move(core)); - } + static_assert(sizeof...(Args) == 1, + "A continuation should only take one single argument"); + + typedef typename detail::nth_element<0, Args...>::type Arg; + + static_assert(std::is_same<T, Arg>::value || + std::is_convertible<T, Arg>::value, + "Incompatible types detected"); + + Continuation(const std::shared_ptr<Core> &chain, Resolve resolve, + Reject reject) + : Continuable<T>(chain), resolve_(resolve), reject_(reject) {} + + void doResolve(const std::shared_ptr<CoreT<T>> &core) override { + auto promise = resolve_(detail::tryMove<Resolve>(core->value())); + finishResolve(promise); + } + + void doReject(const std::shared_ptr<CoreT<T>> &core) override { + reject_(core->exc); + for (const auto &req : core->requests) { + req->reject(core); + } + } + + template <typename PromiseType> struct Chainer { + explicit Chainer(const std::shared_ptr<Private::Core> &core) + : chainCore(core) {} + + void operator()(const PromiseType &val) { + chainCore->construct<PromiseType>(val); + for (const auto &req : chainCore->requests) { + req->resolve(chainCore); + } + } - template<typename Exc> - static Promise<T> - rejected(Exc exc) { - auto core = std::make_shared<Core>(); - core->exc = std::make_exception_ptr(exc); - core->state = State::Rejected; - return Promise<T>(std::move(core)); + std::shared_ptr<Core> chainCore; + }; + + template <typename Promise, + typename Type = typename detail::RemovePromise<Promise>::Type> + Chainer<Type> makeChainer(const Promise &) { + return Chainer<Type>(this->chain_); + } + + template <typename P> void finishResolve(P &promise) { + auto chainer = makeChainer(promise); + std::weak_ptr<Core> weakPtr = this->chain_; + promise.then(std::move(chainer), [weakPtr](std::exception_ptr exc) { + if (auto core = weakPtr.lock()) { + core->exc = std::move(exc); + core->state = State::Rejected; + + for (const auto &req : core->requests) { + req->reject(core); } + } + }); + } + + Resolve resolve_; + Reject reject_; +}; + +// Specialization for a void callback returning a Promise +template <typename Resolve, typename Reject, typename U, typename... Args> +struct Continuation<void, Resolve, Reject, Promise<U>(Args...)> + : public Continuable<void> { + + static_assert(sizeof...(Args) == 0, + "Can not attach a non-void continuation to a void-Promise"); + + Continuation(const std::shared_ptr<Core> &chain, Resolve resolve, + Reject reject) + : Continuable<void>(chain), resolve_(resolve), reject_(reject) {} + + void doResolve(const std::shared_ptr<CoreT<void>> & /*core*/) { + auto promise = resolve_(); + finishResolve(promise); + } + + void doReject(const std::shared_ptr<CoreT<void>> &core) { + reject_(core->exc); + for (const auto &req : core->requests) { + req->reject(core); + } + } - bool isPending() const override { return core_->state == State::Pending; } - bool isFulfilled() const override { return core_->state == State::Fulfilled; } - bool isRejected() const override { return core_->state == State::Rejected; } + template <typename PromiseType, typename Dummy = void> struct Chainer { + explicit Chainer(const std::shared_ptr<Private::Core> &core) + : chainCore(core) {} - template<typename ResolveFunc, typename RejectFunc> - auto - then(ResolveFunc resolveFunc, RejectFunc rejectFunc) - -> Promise< - typename detail::RemovePromise< - typename detail::FunctionTrait<ResolveFunc>::ReturnType - >::Type - > - { + void operator()(const PromiseType &val) { + chainCore->construct<PromiseType>(val); + for (const auto &req : chainCore->requests) { + req->resolve(chainCore); + } + } - typedef typename detail::RemovePromise< - typename detail::FunctionTrait<ResolveFunc>::ReturnType - >::Type RetType; + std::shared_ptr<Core> chainCore; + }; - Promise<RetType> promise; + template <typename Dummy> struct Chainer<void, Dummy> { + explicit Chainer(const std::shared_ptr<Private::Core> &core) + : chainCore(core) {} - typedef Private::Continuation<T, ResolveFunc, RejectFunc, ResolveFunc> Continuation; - std::shared_ptr<Private::Request> req = std::make_shared<Continuation>(promise.core_, resolveFunc, rejectFunc); + void operator()() { + auto core = this->chain_; + core->state = State::Fulfilled; - std::unique_lock<std::mutex> guard(core_->mtx); - if (isFulfilled()) { - req->resolve(core_); - } - else if (isRejected()) { - req->reject(core_); - } + for (const auto &req : chainCore->requests) { + req->resolve(chainCore); + } + } - core_->requests.push_back(req); + std::shared_ptr<Core> chainCore; + }; - return promise; - } + template <typename Promise, + typename Type = typename detail::RemovePromise<Promise>::Type> + Chainer<Type> makeChainer(const Promise &) { + return Chainer<Type>(this->chain_); + } - private: - Promise() - : core_(std::make_shared<Core>()) - , resolver_(core_) - , rejection_(core_) - { - } + template <typename P> void finishResolve(P &promise) { + auto chainer = makeChainer(promise); + promise.then(std::move(chainer), [=](std::exception_ptr exc) { + auto core = this->chain_; + core->exc = std::move(exc); + core->state = State::Rejected; - explicit Promise(std::shared_ptr<Core>&& core) - : core_(core) - , resolver_(core_) - , rejection_(core_) - { } + for (const auto &req : core->requests) { + req->reject(core); + } + }); + } + + Resolve resolve_; + Reject reject_; +}; + +} // namespace impl + +template <typename T, typename Resolve, typename Reject, typename Sig> +struct Continuation : public impl::Continuation<T, Resolve, Reject, + decltype(&Sig::operator())> { + + typedef impl::Continuation<T, Resolve, Reject, decltype(&Sig::operator())> + Base; + + Continuation(const std::shared_ptr<Core> &core, Resolve resolve, + Reject reject) + : Base(core, std::move(resolve), std::move(reject)) {} +}; + +template <typename T, typename Resolve, typename Reject, typename Res, + typename... Args> +struct Continuation<T, Resolve, Reject, Res (*)(Args...)> + : public impl::Continuation<T, Resolve, Reject, Res(Args...)> { + typedef impl::Continuation<T, Resolve, Reject, Res(Args...)> Base; + + Continuation(const std::shared_ptr<Core> &core, Resolve resolve, + Reject reject) + : Base(core, std::move(resolve), std::move(reject)) {} +}; + +template <typename T, typename Resolve, typename Reject, typename Res, + typename Cls, typename... Args> +struct Continuation<T, Resolve, Reject, Res (Cls::*)(Args...)> + : public impl::Continuation<T, Resolve, Reject, Res(Args...)> { + typedef impl::Continuation<T, Resolve, Reject, Res(Args...)> Base; + + Continuation(const std::shared_ptr<Core> &core, Resolve resolve, + Reject reject) + : Base(core, std::move(resolve), std::move(reject)) {} +}; + +template <typename T, typename Resolve, typename Reject, typename Res, + typename Cls, typename... Args> +struct Continuation<T, Resolve, Reject, Res (Cls::*)(Args...) const> + : public impl::Continuation<T, Resolve, Reject, Res(Args...)> { + typedef impl::Continuation<T, Resolve, Reject, Res(Args...)> Base; + + Continuation(const std::shared_ptr<Core> &core, Resolve resolve, + Reject reject) + : Base(core, std::move(resolve), std::move(reject)) {} +}; + +template <typename T, typename Resolve, typename Reject, typename Res, + typename... Args> +struct Continuation<T, Resolve, Reject, std::function<Res(Args...)>> + : public impl::Continuation<T, Resolve, Reject, Res(Args...)> { + typedef impl::Continuation<T, Resolve, Reject, Res(Args...)> Base; + + Continuation(const std::shared_ptr<Core> &core, Resolve resolve, + Reject reject) + : Base(core, std::move(resolve), std::move(reject)) {} +}; +} // namespace Private + +class Resolver { +public: + explicit Resolver(const std::shared_ptr<Private::Core> &core) : core_(core) {} + + Resolver(const Resolver &other) = delete; + Resolver &operator=(const Resolver &other) = delete; + + Resolver(Resolver &&other) = default; + Resolver &operator=(Resolver &&other) = default; + + template <typename Arg> bool operator()(Arg &&arg) const { + if (!core_) + return false; + + typedef typename std::remove_reference<Arg>::type Type; + + if (core_->state != State::Pending) + throw Error("Attempt to resolve a fulfilled promise"); + + /* In a ideal world, this should be checked at compile-time rather + * than runtime. However, since types are erased, this looks like + * a difficult task + */ + if (core_->isVoid()) { + throw Error("Attempt to resolve a void promise with arguments"); + } - std::shared_ptr<Core> core_; - Resolver resolver_; - Rejection rejection_; - }; + std::unique_lock<std::mutex> guard(core_->mtx); + core_->construct<Type>(std::forward<Arg>(arg)); - template<typename T> - class Barrier { - public: - explicit Barrier(Promise<T>& promise) - : promise_(promise) { - } + for (const auto &req : core_->requests) { + req->resolve(core_); + } - void wait() { - if (promise_.isFulfilled() || promise_.isRejected()) return; + return true; + } - promise_.then([&](const T&) mutable { - std::unique_lock<std::mutex> guard(mtx); - cv.notify_one(); - }, [&](std::exception_ptr) mutable { - std::unique_lock<std::mutex> guard(mtx); - cv.notify_one(); - }); + bool operator()() const { + if (!core_) + return false; - std::unique_lock<std::mutex> guard(mtx); - cv.wait(guard, [&] { return promise_.isFulfilled() || promise_.isRejected(); }); - } + if (core_->state != State::Pending) + throw Error("Attempt to resolve a fulfilled promise"); - template<class Rep, class Period> - std::cv_status wait_for(const std::chrono::duration<Rep, Period>& period) { - if (promise_.isFulfilled() || promise_.isRejected()) return std::cv_status::no_timeout; + if (!core_->isVoid()) + throw Error("Attempt ro resolve a non-void promise with no argument"); - promise_.then([&](const T&) mutable { - std::unique_lock<std::mutex> guard(mtx); - cv.notify_one(); - }, [&](std::exception_ptr) mutable { - std::unique_lock<std::mutex> guard(mtx); - cv.notify_one(); - }); + std::unique_lock<std::mutex> guard(core_->mtx); + core_->state = State::Fulfilled; + for (const auto &req : core_->requests) { + req->resolve(core_); + } - std::unique_lock<std::mutex> guard(mtx); - return cv.wait_for(guard, period); - } + return true; + } - private: - Promise<T>& promise_; - mutable std::mutex mtx; - std::condition_variable cv; - }; + void clear() { core_ = nullptr; } + + Resolver clone() { return Resolver(core_); } + +private: + std::shared_ptr<Private::Core> core_; +}; - namespace Impl { - struct Any; +class Rejection { +public: + explicit Rejection(const std::shared_ptr<Private::Core> &core) + : core_(core) {} + + Rejection(const Rejection &other) = delete; + Rejection &operator=(const Rejection &other) = delete; + + Rejection(Rejection &&other) = default; + Rejection &operator=(Rejection &&other) = default; + + template <typename Exc> bool operator()(Exc exc) const { + if (!core_) + return false; + + if (core_->state != State::Pending) + throw Error("Attempt to reject a fulfilled promise"); + + std::unique_lock<std::mutex> guard(core_->mtx); + core_->exc = std::make_exception_ptr(exc); + core_->state = State::Rejected; + for (const auto &req : core_->requests) { + req->reject(core_); } - class Any { - public: - friend struct Impl::Any; + return true; + } - Any(const Any& other) = default; - Any& operator=(const Any& other) = default; + void clear() { core_ = nullptr; } - Any(Any&& other) = default; - Any& operator=(Any&& other) = default; + Rejection clone() { return Rejection(core_); } - template<typename T> - bool is() const { - return core_->id == TypeId::of<T>(); - } +private: + std::shared_ptr<Private::Core> core_; +}; - template<typename T> - T cast() const { - if (!is<T>()) throw BadAnyCast(); +template <typename T> class Deferred { +public: + Deferred() : resolver(nullptr), rejection(nullptr) {} - auto core = std::static_pointer_cast<Private::CoreT<T>>(core_); - return core->value(); - } + Deferred(const Deferred &other) = delete; + Deferred &operator=(const Deferred &other) = delete; - private: - explicit Any(const std::shared_ptr<Private::Core>& core) - : core_(core) - { } - std::shared_ptr<Private::Core> core_; + Deferred(Deferred &&other) = default; + Deferred &operator=(Deferred &&other) = default; - }; + Deferred(Resolver _resolver, Rejection _reject) + : resolver(std::move(_resolver)), rejection(std::move(_reject)) {} + + template <typename U> bool resolve(U &&arg) { + typedef typename std::remove_reference<U>::type CleanU; + + static_assert(std::is_same<T, CleanU>::value || + std::is_convertible<U, T>::value, + "Types mismatch"); + + return resolver(std::forward<U>(arg)); + } + + template <typename... Args> void emplaceResolve(Args &&...) {} + + template <typename Exc> bool reject(Exc exc) { + return rejection(std::move(exc)); + } + + void clear() { + resolver.clear(); + rejection.clear(); + } + +private: + Resolver resolver; + Rejection rejection; +}; + +template <> class Deferred<void> { +public: + Deferred() : resolver(nullptr), rejection(nullptr) {} + + Deferred(const Deferred &other) = delete; + Deferred &operator=(const Deferred &other) = delete; + + Deferred(Deferred &&other) = default; + Deferred &operator=(Deferred &&other) = default; - namespace Impl { + Deferred(Resolver _resolver, Rejection _reject) + : resolver(std::move(_resolver)), rejection(std::move(_reject)) {} - /* Instead of duplicating the code between whenAll and whenAny functions, the main implementation - * is in the When class below and we configure the class with a policy instead, depending if we - * are executing an "all" or "any" operation, how cool is that ? - */ - struct All { + void resolve() { resolver(); } - struct Data { - Data(const size_t _total, Resolver _resolver, Rejection _rejection) - : total(_total) - , resolved(0) - , rejected(false) - , mtx() - , resolve(std::move(_resolver)) - , reject(std::move(_rejection)) - { } + template <typename Exc> void reject(Exc _exc) { rejection(std::move(_exc)); } - const size_t total; - size_t resolved; - bool rejected; - std::mutex mtx; - - Resolver resolve; - Rejection reject; - }; - - template<size_t Index, typename T, typename Data> - static void resolveT(const T& val, Data& data) { - std::lock_guard<std::mutex> guard(data->mtx); - - if (data->rejected) return; - - // @Check thread-safety of std::get ? - std::get<Index>(data->results) = val; - data->resolved++; - - if (data->resolved == data->total) { - data->resolve(data->results); - } - } - - template<typename Data> - static void resolveVoid(Data& data) { - std::lock_guard<std::mutex> guard(data->mtx); - - if (data->rejected) return; - - data->resolved++; - - if (data->resolved == data->total) { - data->resolve(data->results); - } - } - - template<typename Data> - static void reject(std::exception_ptr exc, Data& data) { - std::lock_guard<std::mutex> guard(data->mtx); - - data->rejected = true; - data->reject(exc); - } - }; - - struct Any { - - struct Data { - Data(size_t, Resolver resolver, Rejection rejection) - : done(false) - , mtx() - , resolve(std::move(resolver)) - , reject(std::move(rejection)) - { } - - bool done; - std::mutex mtx; - - Resolver resolve; - Rejection reject; - }; - - template<size_t Index, typename T, typename Data> - static void resolveT(const T& val, Data& data) { - std::lock_guard<std::mutex> guard(data->mtx); - - if (data->done) return; - - // Instead of allocating a new core, ideally we could share the same core as - // the relevant promise but we do not have access to the promise here is so meh - auto core = std::make_shared<Private::CoreT<T>>(); - core->template construct<T>(val); - data->resolve(Async::Any(core)); - - data->done = true; - } - - template<typename Data> - static void resolveVoid(Data& data) { - std::lock_guard<std::mutex> guard(data->mtx); - - if (data->done) return; - - auto core = std::make_shared<Private::CoreT<void>>(); - data->resolve(Async::Any(core)); - - data->done = true; - } - - template<typename Data> - static void reject(std::exception_ptr exc, Data& data) { - std::lock_guard<std::mutex> guard(data->mtx); - - data->done = true; - data->reject(exc); - } - }; - - template<typename ContinuationPolicy> - struct When { - When(Resolver resolver, Rejection rejection) - : resolve(std::move(resolver)) - , reject(std::move(rejection)) - { } - - template<typename... Args> - void operator()(Args&&... args) { - whenArgs(std::forward<Args>(args)...); - } - - private: - template<typename T, size_t Index, typename Data> - struct WhenContinuation { - explicit WhenContinuation(Data _data) - : data(std::move(_data)) - { } - - void operator()(const T& val) const { - ContinuationPolicy::template resolveT<Index>(val, data); - } - - Data data; - }; - - template<size_t Index, typename Data> - struct WhenContinuation<void, Index, Data> { - explicit WhenContinuation(Data _data) - : data(std::move(_data)) - { } - - void operator()() const { - ContinuationPolicy::resolveVoid(data); - } - - Data data; - - }; - - template<typename T, size_t Index, typename Data> - WhenContinuation<T, Index, Data> - makeContinuation(const Data& data) { - return WhenContinuation<T, Index, Data>(data); - } - - template<size_t Index, typename Data, typename T> - void when(const Data& data, Promise<T>& promise) { - promise.then(makeContinuation<T, Index>(data), [=](std::exception_ptr ptr) { - ContinuationPolicy::reject(std::move(ptr), data); - }); - } - - template<size_t Index, typename Data, typename T> - void when(const Data& data, T&& arg) { - typedef typename std::remove_reference<T>::type CleanT; - auto promise = Promise<CleanT>::resolved(std::forward<T>(arg)); - when<Index>(data, promise); - } - - template<typename... Args> - void whenArgs(Args&& ...args) { - typedef std::tuple< - typename detail::RemovePromise< - typename std::remove_reference<Args>::type - >::Type... - > Results; - /* We need to keep the results alive until the last promise - * finishes its execution - */ - - /* See the trick here ? Basically, we only have access to the real type of the results - * in this function. The policy classes do not have access to the full type (std::tuple), - * but, instead, take a generic template data type as a parameter. They only need to know - * that results is a tuple, they do not need to know the real type of the results. - * - * This is some sort of compile-time template type-erasing, hue - */ - struct Data : public ContinuationPolicy::Data { - Data(size_t total, Resolver resolver, Rejection rejection) - : ContinuationPolicy::Data(total, std::move(resolver), std::move(rejection)) - { } - - Results results; - }; - - auto data = std::make_shared<Data>(sizeof...(Args), std::move(resolve), std::move(reject)); - whenArgs<0>(data, std::forward<Args>(args)...); - } - - template<size_t Index, typename Data, typename Head, typename... Rest> - void whenArgs(const Data& data, Head&& head, Rest&& ...rest) { - when<Index>(data, std::forward<Head>(head)); - whenArgs<Index + 1>(data, std::forward<Rest>(rest)...); - } - - template<size_t Index, typename Data, typename Head> - void whenArgs(const Data& data, Head&& head) { - when<Index>(data, std::forward<Head>(head)); - } - - Resolver resolve; - Rejection reject; - }; - - template< - typename T, - typename Results - > - struct WhenAllRange - { - WhenAllRange(Resolver _resolve, Rejection _reject) - : resolve(std::move(_resolve)) - , reject(std::move(_reject)) - { } - - template<typename Iterator> - void operator()(Iterator first, Iterator last) - { - auto data = std::make_shared<DataT<T>>( - static_cast<size_t>(std::distance(first, last)), - std::move(resolve), - std::move(reject) - ); - - size_t index = 0; - for (auto it = first; it != last; ++it) { - - WhenContinuation<T> cont(data, index); - - it->then(std::move(cont), [=](std::exception_ptr ptr) { - std::lock_guard<std::mutex> guard(data->mtx); - - if (data->rejected) return; - - data->rejected = true; - data->reject(std::move(ptr)); - }); - - ++index; - } - } - - private: - struct Data - { - Data(size_t _total, Resolver _resolver, Rejection _rejection) - : total(_total) - , resolved(0) - , rejected(false) - , mtx() - , resolve(std::move(_resolver)) - , reject(std::move(_rejection)) - { } - - const size_t total; - size_t resolved; - bool rejected; - std::mutex mtx; - - Resolver resolve; - Rejection reject; - }; - - /* Ok so apparently I can not fully specialize a template structure - * here, so you know what, compiler ? Take that Dummy type and leave - * me alone - */ - template<typename ValueType, typename Dummy = void> struct DataT : public Data { - DataT(size_t total, Resolver resolver, Rejection rejection) - : Data(total, std::move(resolver), std::move(rejection)) - { - results.resize(total); - } - - Results results; - }; - - /* For a vector of void promises, we do not have any results, that's - * why we need a distinct specialization for the void case - */ - template<typename Dummy> struct DataT<void, Dummy> : public Data { - DataT(size_t total, Resolver resolver, Rejection rejection) - : Data(total, std::move(resolver), std::move(rejection)) - { - } - }; - - template<typename ValueType, typename Dummy = void> - struct WhenContinuation - { - using D = std::shared_ptr<DataT<ValueType>>; - - WhenContinuation(const D& _data, size_t _index) - : data(_data) - , index(_index) - { } - - void operator()(const ValueType& val) const - { - std::lock_guard<std::mutex> guard(data->mtx); - - if (data->rejected) return; - - data->results[index] = val; - data->resolved++; - if (data->resolved == data->total) - { - data->resolve(data->results); - } - } - - D data; - size_t index; - }; - - template<typename Dummy> - struct WhenContinuation<void, Dummy> - { - using D = std::shared_ptr<DataT<void>>; - - WhenContinuation(const D& _data, size_t) - : data(_data) - { } - - void operator()() const - { - std::lock_guard<std::mutex> guard(data->mtx); - - if (data->rejected) return; - - data->resolved++; - if (data->resolved == data->total) - { - data->resolve(); - } - } - - D data; - }; - - Resolver resolve; - Rejection reject; - }; +private: + Resolver resolver; + Rejection rejection; +}; +static constexpr Private::IgnoreException IgnoreException{}; +static constexpr Private::NoExcept NoExcept{}; +static constexpr Private::Throw Throw{}; + +namespace details { + +/* + * Note that we could use std::result_of to SFINAE-out and dispatch to the right + * call However, gcc 4.7 does not correctly support std::result_of for SFINAE + * purposes, so we use a decltype SFINAE-expression instead. + * + * See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3462.html and + * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56283 for reference + */ +template <typename T, typename Func> +auto callAsync(Func func, Resolver &resolver, Rejection &rejection) + -> decltype(std::declval<Func>()(resolver, rejection), void()) { + func(resolver, rejection); +} + +template <typename T, typename Func> +auto callAsync(Func func, Resolver &resolver, Rejection &rejection) + -> decltype(std::declval<Func>()(Deferred<T>()), void()) { + func(Deferred<T>(std::move(resolver), std::move(rejection))); +} +} // namespace details + +template <typename T> class Promise : public PromiseBase { +public: + template <typename U> friend class Promise; + + typedef Private::CoreT<T> Core; + + template <typename Func> + explicit Promise(Func func) + : core_(std::make_shared<Core>()), resolver_(core_), rejection_(core_) { + details::callAsync<T>(func, resolver_, rejection_); + } + + Promise(const Promise<T> &other) = delete; + Promise &operator=(const Promise<T> &other) = delete; + + Promise(Promise<T> &&other) = default; + Promise &operator=(Promise<T> &&other) = default; + + virtual ~Promise() {} + + template <typename U> static Promise<T> resolved(U &&value) { + static_assert(!std::is_void<T>::value, + "Can not resolve a void promise with parameters"); + static_assert(std::is_same<T, U>::value || std::is_convertible<U, T>::value, + "Incompatible value type"); + + auto core = std::make_shared<Core>(); + core->template construct<T>(std::forward<U>(value)); + return Promise<T>(std::move(core)); + } + + static Promise<void> resolved() { + static_assert(std::is_void<T>::value, + "Resolving a non-void promise requires parameters"); + + auto core = std::make_shared<Core>(); + core->state = State::Fulfilled; + return Promise<T>(std::move(core)); + } + + template <typename Exc> static Promise<T> rejected(Exc exc) { + auto core = std::make_shared<Core>(); + core->exc = std::make_exception_ptr(exc); + core->state = State::Rejected; + return Promise<T>(std::move(core)); + } + + bool isPending() const override { return core_->state == State::Pending; } + bool isFulfilled() const override { return core_->state == State::Fulfilled; } + bool isRejected() const override { return core_->state == State::Rejected; } + + template <typename ResolveFunc, typename RejectFunc> + auto then(ResolveFunc resolveFunc, RejectFunc rejectFunc) + -> Promise<typename detail::RemovePromise< + typename detail::FunctionTrait<ResolveFunc>::ReturnType>::Type> { + + typedef typename detail::RemovePromise< + typename detail::FunctionTrait<ResolveFunc>::ReturnType>::Type RetType; + + Promise<RetType> promise; + + typedef Private::Continuation<T, ResolveFunc, RejectFunc, ResolveFunc> + Continuation; + std::shared_ptr<Private::Request> req = + std::make_shared<Continuation>(promise.core_, resolveFunc, rejectFunc); + + std::unique_lock<std::mutex> guard(core_->mtx); + if (isFulfilled()) { + req->resolve(core_); + } else if (isRejected()) { + req->reject(core_); } - template< - typename... Args, - typename Results = - std::tuple< - typename detail::RemovePromise< - typename std::remove_reference<Args>::type - >::Type... - > - > - Promise<Results> whenAll(Args&& ...args) { - // As ugly as it looks, this is needed to bypass a bug of gcc < 4.9 - // whereby template parameters pack inside a lambda expression are not - // captured correctly and can not be expanded inside the lambda. - Resolver* resolve; - Rejection* reject; - - Promise<Results> promise([&](Resolver& resolver, Rejection& rejection) { - resolve = &resolver; - reject = &rejection; + core_->requests.push_back(req); + + return promise; + } + +private: + Promise() + : core_(std::make_shared<Core>()), resolver_(core_), rejection_(core_) {} + + explicit Promise(std::shared_ptr<Core> &&core) + : core_(core), resolver_(core_), rejection_(core_) {} + + std::shared_ptr<Core> core_; + Resolver resolver_; + Rejection rejection_; +}; + +template <typename T> class Barrier { +public: + explicit Barrier(Promise<T> &promise) : promise_(promise) {} + + void wait() { + if (promise_.isFulfilled() || promise_.isRejected()) + return; + + promise_.then( + [&](const T &) mutable { + std::unique_lock<std::mutex> guard(mtx); + cv.notify_one(); + }, + [&](std::exception_ptr) mutable { + std::unique_lock<std::mutex> guard(mtx); + cv.notify_one(); + }); + + std::unique_lock<std::mutex> guard(mtx); + cv.wait(guard, + [&] { return promise_.isFulfilled() || promise_.isRejected(); }); + } + + template <class Rep, class Period> + std::cv_status wait_for(const std::chrono::duration<Rep, Period> &period) { + if (promise_.isFulfilled() || promise_.isRejected()) + return std::cv_status::no_timeout; + + promise_.then( + [&](const T &) mutable { + std::unique_lock<std::mutex> guard(mtx); + cv.notify_one(); + }, + [&](std::exception_ptr) mutable { + std::unique_lock<std::mutex> guard(mtx); + cv.notify_one(); }); - Impl::When<Impl::All> impl(std::move(*resolve), std::move(*reject)); - // So we capture everything we need inside the lambda and then call the - // implementation and expand the parameters pack here - impl(std::forward<Args>(args)...); + std::unique_lock<std::mutex> guard(mtx); + return cv.wait_for(guard, period); + } + +private: + Promise<T> &promise_; + mutable std::mutex mtx; + std::condition_variable cv; +}; + +namespace Impl { +struct Any; +} + +class Any { +public: + friend struct Impl::Any; + + Any(const Any &other) = default; + Any &operator=(const Any &other) = default; + + Any(Any &&other) = default; + Any &operator=(Any &&other) = default; + + template <typename T> bool is() const { return core_->id == TypeId::of<T>(); } + + template <typename T> T cast() const { + if (!is<T>()) + throw BadAnyCast(); + + auto core = std::static_pointer_cast<Private::CoreT<T>>(core_); + return core->value(); + } + +private: + explicit Any(const std::shared_ptr<Private::Core> &core) : core_(core) {} + std::shared_ptr<Private::Core> core_; +}; - return promise; +namespace Impl { + +/* Instead of duplicating the code between whenAll and whenAny functions, the + * main implementation is in the When class below and we configure the class + * with a policy instead, depending if we are executing an "all" or "any" + * operation, how cool is that ? + */ +struct All { + + struct Data { + Data(const size_t _total, Resolver _resolver, Rejection _rejection) + : total(_total), resolved(0), rejected(false), mtx(), + resolve(std::move(_resolver)), reject(std::move(_rejection)) {} + + const size_t total; + size_t resolved; + bool rejected; + std::mutex mtx; + + Resolver resolve; + Rejection reject; + }; + + template <size_t Index, typename T, typename Data> + static void resolveT(const T &val, Data &data) { + std::lock_guard<std::mutex> guard(data->mtx); + + if (data->rejected) + return; + + // @Check thread-safety of std::get ? + std::get<Index>(data->results) = val; + data->resolved++; + + if (data->resolved == data->total) { + data->resolve(data->results); } + } - template<typename... Args> - Promise<Any> whenAny(Args&& ...args) { - // Same trick as above; - Resolver* resolve; - Rejection* reject; + template <typename Data> static void resolveVoid(Data &data) { + std::lock_guard<std::mutex> guard(data->mtx); - Promise<Any> promise([&](Resolver& resolver, Rejection& rejection) { - resolve = &resolver; - reject = &rejection; - }); + if (data->rejected) + return; - Impl::When<Impl::Any> impl(std::move(*resolve), std::move(*reject)); - impl(std::forward<Args>(args)...); - return promise; + data->resolved++; + + if (data->resolved == data->total) { + data->resolve(data->results); } + } - template< - typename Iterator, - typename ValueType - = typename detail::RemovePromise< - typename std::iterator_traits<Iterator>::value_type - >::Type, - typename Results - = typename std::conditional< - std::is_same<void, ValueType>::value, - void, std::vector<ValueType> - >::type - > - Promise<Results> whenAll(Iterator first, Iterator last) { - /* @Security, assert that last >= first */ + template <typename Data> + static void reject(std::exception_ptr exc, Data &data) { + std::lock_guard<std::mutex> guard(data->mtx); - return Promise<Results>([=](Resolver& resolve, Rejection& rejection) { + data->rejected = true; + data->reject(exc); + } +}; - Impl::WhenAllRange<ValueType, Results> impl( - std::move(resolve), std::move(rejection)); +struct Any { - impl(first, last); + struct Data { + Data(size_t, Resolver resolver, Rejection rejection) + : done(false), mtx(), resolve(std::move(resolver)), + reject(std::move(rejection)) {} - }); + bool done; + std::mutex mtx; + + Resolver resolve; + Rejection reject; + }; + + template <size_t Index, typename T, typename Data> + static void resolveT(const T &val, Data &data) { + std::lock_guard<std::mutex> guard(data->mtx); + + if (data->done) + return; + + // Instead of allocating a new core, ideally we could share the same core as + // the relevant promise but we do not have access to the promise here is so + // meh + auto core = std::make_shared<Private::CoreT<T>>(); + core->template construct<T>(val); + data->resolve(Async::Any(core)); + + data->done = true; + } + + template <typename Data> static void resolveVoid(Data &data) { + std::lock_guard<std::mutex> guard(data->mtx); + + if (data->done) + return; + + auto core = std::make_shared<Private::CoreT<void>>(); + data->resolve(Async::Any(core)); + + data->done = true; + } + + template <typename Data> + static void reject(std::exception_ptr exc, Data &data) { + std::lock_guard<std::mutex> guard(data->mtx); + + data->done = true; + data->reject(exc); + } +}; + +template <typename ContinuationPolicy> struct When { + When(Resolver resolver, Rejection rejection) + : resolve(std::move(resolver)), reject(std::move(rejection)) {} + + template <typename... Args> void operator()(Args &&... args) { + whenArgs(std::forward<Args>(args)...); + } + +private: + template <typename T, size_t Index, typename Data> struct WhenContinuation { + explicit WhenContinuation(Data _data) : data(std::move(_data)) {} + + void operator()(const T &val) const { + ContinuationPolicy::template resolveT<Index>(val, data); + } + + Data data; + }; + + template <size_t Index, typename Data> + struct WhenContinuation<void, Index, Data> { + explicit WhenContinuation(Data _data) : data(std::move(_data)) {} + + void operator()() const { ContinuationPolicy::resolveVoid(data); } + + Data data; + }; + + template <typename T, size_t Index, typename Data> + WhenContinuation<T, Index, Data> makeContinuation(const Data &data) { + return WhenContinuation<T, Index, Data>(data); + } + + template <size_t Index, typename Data, typename T> + void when(const Data &data, Promise<T> &promise) { + promise.then(makeContinuation<T, Index>(data), [=](std::exception_ptr ptr) { + ContinuationPolicy::reject(std::move(ptr), data); + }); + } + + template <size_t Index, typename Data, typename T> + void when(const Data &data, T &&arg) { + typedef typename std::remove_reference<T>::type CleanT; + auto promise = Promise<CleanT>::resolved(std::forward<T>(arg)); + when<Index>(data, promise); + } + + template <typename... Args> void whenArgs(Args &&... args) { + typedef std::tuple<typename detail::RemovePromise< + typename std::remove_reference<Args>::type>::Type...> + Results; + /* We need to keep the results alive until the last promise + * finishes its execution + */ + + /* See the trick here ? Basically, we only have access to the real type of + * the results in this function. The policy classes do not have access to + * the full type (std::tuple), but, instead, take a generic template data + * type as a parameter. They only need to know that results is a tuple, they + * do not need to know the real type of the results. + * + * This is some sort of compile-time template type-erasing, hue + */ + struct Data : public ContinuationPolicy::Data { + Data(size_t total, Resolver resolver, Rejection rejection) + : ContinuationPolicy::Data(total, std::move(resolver), + std::move(rejection)) {} + + Results results; + }; + + auto data = std::make_shared<Data>(sizeof...(Args), std::move(resolve), + std::move(reject)); + whenArgs<0>(data, std::forward<Args>(args)...); + } + + template <size_t Index, typename Data, typename Head, typename... Rest> + void whenArgs(const Data &data, Head &&head, Rest &&... rest) { + when<Index>(data, std::forward<Head>(head)); + whenArgs<Index + 1>(data, std::forward<Rest>(rest)...); + } + + template <size_t Index, typename Data, typename Head> + void whenArgs(const Data &data, Head &&head) { + when<Index>(data, std::forward<Head>(head)); + } + + Resolver resolve; + Rejection reject; +}; + +template <typename T, typename Results> struct WhenAllRange { + WhenAllRange(Resolver _resolve, Rejection _reject) + : resolve(std::move(_resolve)), reject(std::move(_reject)) {} + + template <typename Iterator> void operator()(Iterator first, Iterator last) { + auto data = std::make_shared<DataT<T>>( + static_cast<size_t>(std::distance(first, last)), std::move(resolve), + std::move(reject)); + + size_t index = 0; + for (auto it = first; it != last; ++it) { + + WhenContinuation<T> cont(data, index); + + it->then(std::move(cont), [=](std::exception_ptr ptr) { + std::lock_guard<std::mutex> guard(data->mtx); + + if (data->rejected) + return; + + data->rejected = true; + data->reject(std::move(ptr)); + }); + + ++index; + } + } + +private: + struct Data { + Data(size_t _total, Resolver _resolver, Rejection _rejection) + : total(_total), resolved(0), rejected(false), mtx(), + resolve(std::move(_resolver)), reject(std::move(_rejection)) {} + + const size_t total; + size_t resolved; + bool rejected; + std::mutex mtx; + + Resolver resolve; + Rejection reject; + }; + + /* Ok so apparently I can not fully specialize a template structure + * here, so you know what, compiler ? Take that Dummy type and leave + * me alone + */ + template <typename ValueType, typename Dummy = void> + struct DataT : public Data { + DataT(size_t total, Resolver resolver, Rejection rejection) + : Data(total, std::move(resolver), std::move(rejection)) { + results.resize(total); + } + + Results results; + }; + + /* For a vector of void promises, we do not have any results, that's + * why we need a distinct specialization for the void case + */ + template <typename Dummy> struct DataT<void, Dummy> : public Data { + DataT(size_t total, Resolver resolver, Rejection rejection) + : Data(total, std::move(resolver), std::move(rejection)) {} + }; + + template <typename ValueType, typename Dummy = void> struct WhenContinuation { + using D = std::shared_ptr<DataT<ValueType>>; + + WhenContinuation(const D &_data, size_t _index) + : data(_data), index(_index) {} + + void operator()(const ValueType &val) const { + std::lock_guard<std::mutex> guard(data->mtx); + + if (data->rejected) + return; + + data->results[index] = val; + data->resolved++; + if (data->resolved == data->total) { + data->resolve(data->results); + } + } + + D data; + size_t index; + }; + + template <typename Dummy> struct WhenContinuation<void, Dummy> { + using D = std::shared_ptr<DataT<void>>; + + WhenContinuation(const D &_data, size_t) : data(_data) {} + + void operator()() const { + std::lock_guard<std::mutex> guard(data->mtx); + + if (data->rejected) + return; + + data->resolved++; + if (data->resolved == data->total) { + data->resolve(); + } } + D data; + }; + + Resolver resolve; + Rejection reject; +}; + +} // namespace Impl + +template <typename... Args, + typename Results = std::tuple<typename detail::RemovePromise< + typename std::remove_reference<Args>::type>::Type...>> +Promise<Results> whenAll(Args &&... args) { + // As ugly as it looks, this is needed to bypass a bug of gcc < 4.9 + // whereby template parameters pack inside a lambda expression are not + // captured correctly and can not be expanded inside the lambda. + Resolver *resolve; + Rejection *reject; + + Promise<Results> promise([&](Resolver &resolver, Rejection &rejection) { + resolve = &resolver; + reject = &rejection; + }); + + Impl::When<Impl::All> impl(std::move(*resolve), std::move(*reject)); + // So we capture everything we need inside the lambda and then call the + // implementation and expand the parameters pack here + impl(std::forward<Args>(args)...); + + return promise; +} + +template <typename... Args> Promise<Any> whenAny(Args &&... args) { + // Same trick as above; + Resolver *resolve; + Rejection *reject; + + Promise<Any> promise([&](Resolver &resolver, Rejection &rejection) { + resolve = &resolver; + reject = &rejection; + }); + + Impl::When<Impl::Any> impl(std::move(*resolve), std::move(*reject)); + impl(std::forward<Args>(args)...); + return promise; +} + +template <typename Iterator, + typename ValueType = typename detail::RemovePromise< + typename std::iterator_traits<Iterator>::value_type>::Type, + typename Results = + typename std::conditional<std::is_same<void, ValueType>::value, + void, std::vector<ValueType>>::type> +Promise<Results> whenAll(Iterator first, Iterator last) { + /* @Security, assert that last >= first */ + + return Promise<Results>([=](Resolver &resolve, Rejection &rejection) { + Impl::WhenAllRange<ValueType, Results> impl(std::move(resolve), + std::move(rejection)); + + impl(first, last); + }); +} + } // namespace Async } // namespace Pistache diff --git a/include/pistache/router.h b/include/pistache/router.h index 03468582a8146ac21968159da5522256b9f1c5c6..60008c0c8b0a83e5bb6402c6c34da6e68446add7 100644 --- a/include/pistache/router.h +++ b/include/pistache/router.h @@ -255,7 +255,8 @@ public: */ explicit RouterHandler(std::shared_ptr<Rest::Router> router); - void onRequest(const Http::Request &req, Http::ResponseWriter response) override; + void onRequest(const Http::Request &req, + Http::ResponseWriter response) override; private: std::shared_ptr<Tcp::Handler> clone() const final {