Unverified Commit 1b57112a authored by Dennis Jenkins's avatar Dennis Jenkins Committed by GitHub

Merge pull request #696 from dennisjenkins75/master

Ran clang-format on all headers (except date.h, since its not ours).
parents a6c8da47 352afa52
...@@ -9,201 +9,179 @@ ...@@ -9,201 +9,179 @@
#include <pistache/typeid.h> #include <pistache/typeid.h>
#include <type_traits> #include <atomic>
#include <condition_variable>
#include <functional> #include <functional>
#include <memory> #include <memory>
#include <atomic>
#include <vector>
#include <mutex> #include <mutex>
#include <condition_variable>
#include <stdexcept> #include <stdexcept>
#include <type_traits>
#include <typeinfo> #include <typeinfo>
#include <vector>
namespace Pistache { namespace Pistache {
namespace Async { namespace Async {
class Error : public std::runtime_error { class Error : public std::runtime_error {
public: public:
explicit Error(const char* what) : std::runtime_error(what) { } explicit Error(const char *what) : std::runtime_error(what) {}
explicit Error(const std::string& what) : std::runtime_error(what) { } explicit Error(const std::string &what) : std::runtime_error(what) {}
}; };
class BadType : public Error { class BadType : public Error {
public: public:
explicit BadType(TypeId id) explicit BadType(TypeId id)
: Error("Argument type can not be used to resolve the promise " : Error("Argument type can not be used to resolve the promise "
" (TypeId does not match)") " (TypeId does not match)"),
, id_(std::move(id)) id_(std::move(id)) {}
{ }
TypeId typeId() const { TypeId typeId() const { return id_; }
return id_;
}
private: private:
TypeId id_; TypeId id_;
}; };
class BadAnyCast : public std::bad_cast { class BadAnyCast : public std::bad_cast {
public: public:
const char* what() const noexcept override { return "Bad any cast"; } const char *what() const noexcept override { return "Bad any cast"; }
virtual ~BadAnyCast() { } virtual ~BadAnyCast() {}
}; };
enum class State { enum class State { Pending, Fulfilled, Rejected };
Pending, Fulfilled, Rejected
};
template<typename T> class Promise; template <typename T> class Promise;
class PromiseBase { class PromiseBase {
public: public:
virtual ~PromiseBase() { } virtual ~PromiseBase() {}
virtual bool isPending() const = 0; virtual bool isPending() const = 0;
virtual bool isFulfilled() const = 0; virtual bool isFulfilled() const = 0;
virtual bool isRejected() const = 0; virtual bool isRejected() const = 0;
bool isSettled() const { return isFulfilled() || isRejected(); } bool isSettled() const { return isFulfilled() || isRejected(); }
}; };
namespace detail { namespace detail {
template<typename Func, typename T> template <typename Func, typename T> struct IsCallable {
struct IsCallable {
template<typename U> template <typename U>
static auto test(U *) -> decltype(std::declval<Func>()(std::declval<U>()), std::true_type()); static auto test(U *)
-> decltype(std::declval<Func>()(std::declval<U>()), std::true_type());
template<typename U> template <typename U> static auto test(...) -> std::false_type;
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> template <typename Func>
struct IsMoveCallable : public IsMoveCallable<decltype(&Func::operator())> { }; struct IsMoveCallable : public IsMoveCallable<decltype(&Func::operator())> {};
template<typename R, typename Class, typename Arg> template <typename R, typename Class, typename Arg>
struct IsMoveCallable<R (Class::*)(Arg) const> : public std::is_rvalue_reference<Arg> { }; struct IsMoveCallable<R (Class::*)(Arg) const>
: public std::is_rvalue_reference<Arg> {};
template<typename Func, typename Arg> template <typename Func, typename Arg>
typename std::conditional< typename std::conditional<IsMoveCallable<Func>::value, Arg &&,
IsMoveCallable<Func>::value, const Arg &>::type
Arg&&, tryMove(Arg &arg) {
const Arg&
>::type tryMove(Arg& arg) {
return std::move(arg); return std::move(arg);
} }
template<typename Func> template <typename Func>
struct FunctionTrait : public FunctionTrait<decltype(&Func::operator())> { }; struct FunctionTrait : public FunctionTrait<decltype(&Func::operator())> {};
template<typename R, typename Class, typename... Args> template <typename R, typename Class, typename... Args>
struct FunctionTrait<R (Class::*)(Args...) const> { struct FunctionTrait<R (Class::*)(Args...) const> {
typedef R ReturnType; typedef R ReturnType;
static constexpr size_t ArgsCount = sizeof...(Args); static constexpr size_t ArgsCount = sizeof...(Args);
}; };
template<typename R, typename Class, typename... Args> template <typename R, typename Class, typename... Args>
struct FunctionTrait<R (Class::*)(Args...)> { struct FunctionTrait<R (Class::*)(Args...)> {
typedef R ReturnType; typedef R ReturnType;
static constexpr size_t ArgsCount = sizeof...(Args); static constexpr size_t ArgsCount = sizeof...(Args);
}; };
template<typename T> template <typename T> struct RemovePromise { typedef T Type; };
struct RemovePromise {
typedef T Type;
};
template<typename T> template <typename T> struct RemovePromise<Promise<T>> { typedef T Type; };
struct RemovePromise<Promise<T>> {
typedef T Type;
};
template<size_t N, typename... T> struct nth_element; template <size_t N, typename... T> struct nth_element;
template<typename Head, typename... Tail> template <typename Head, typename... Tail>
struct nth_element<0, Head, Tail...> { struct nth_element<0, Head, Tail...> {
typedef Head type; typedef Head type;
}; };
template<size_t N, typename Head, typename... Tail> template <size_t N, typename Head, typename... Tail>
struct nth_element<N, Head, Tail...> { struct nth_element<N, Head, Tail...> {
typedef typename nth_element<N - 1, Tail...>::type type; typedef typename nth_element<N - 1, Tail...>::type type;
}; };
} } // namespace detail
namespace Private { namespace Private {
struct InternalRethrow { struct InternalRethrow {
explicit InternalRethrow(std::exception_ptr _exc) explicit InternalRethrow(std::exception_ptr _exc) : exc(std::move(_exc)) {}
: exc(std::move(_exc))
{ }
std::exception_ptr exc; std::exception_ptr exc;
}; };
struct IgnoreException { struct IgnoreException {
void operator()(std::exception_ptr) const { } void operator()(std::exception_ptr) const {}
}; };
struct NoExcept { struct NoExcept {
void operator()(std::exception_ptr) const { std::terminate(); } void operator()(std::exception_ptr) const { std::terminate(); }
}; };
struct Throw { struct Throw {
void operator()(std::exception_ptr exc) const { void operator()(std::exception_ptr exc) const {
throw InternalRethrow(std::move(exc)); throw InternalRethrow(std::move(exc));
} }
}; };
struct Core; struct Core;
class Request { class Request {
public: public:
virtual void resolve(const std::shared_ptr<Core>& core) = 0; virtual void resolve(const std::shared_ptr<Core> &core) = 0;
virtual void reject(const std::shared_ptr<Core>& core) = 0; virtual void reject(const std::shared_ptr<Core> &core) = 0;
virtual ~Request() {} virtual ~Request() {}
}; };
struct Core { struct Core {
Core(State _state, TypeId _id) Core(State _state, TypeId _id)
: allocated(false) : allocated(false), state(_state), exc(), mtx(), requests(), id(_id) {}
, state(_state)
, exc()
, mtx()
, requests()
, id(_id)
{ }
bool allocated; bool allocated;
std::atomic<State> state; std::atomic<State> state;
std::exception_ptr exc; std::exception_ptr exc;
/* /*
* We need this lock because a Promise might be resolved or rejected from a thread A * We need this lock because a Promise might be resolved or rejected from a
* while a continuation to the same Promise (Core) might be attached at the same from * thread A while a continuation to the same Promise (Core) might be attached
* a thread B. If that's the case, then we need to serialize operations so that we * at the same from a thread B. If that's the case, then we need to serialize
* avoid a race-condition. * 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 * Since we have a lock, we have a blocking progress guarantee but I don't
* to be a major bottleneck as I don't expect major contention on the lock * expect this to be a major bottleneck as I don't expect major contention on
* If it ends up being a bottlenick, try @improving it by experimenting with a lock-free * the lock If it ends up being a bottlenick, try @improving it by
* scheme * experimenting with a lock-free scheme
*/ */
std::mutex mtx; std::mutex mtx;
std::vector<std::shared_ptr<Request>> requests; std::vector<std::shared_ptr<Request>> requests;
TypeId id; TypeId id;
virtual void* memory() = 0; virtual void *memory() = 0;
virtual bool isVoid() const = 0; virtual bool isVoid() const = 0;
template<typename T, typename... Args> template <typename T, typename... Args> void construct(Args &&... args) {
void construct(Args&&... args) {
if (isVoid()) if (isVoid())
throw Error("Can not construct a void core"); throw Error("Can not construct a void core");
...@@ -214,7 +192,7 @@ namespace Async { ...@@ -214,7 +192,7 @@ namespace Async {
void *mem = memory(); void *mem = memory();
if (allocated) { if (allocated) {
reinterpret_cast<T*>(mem)->~T(); reinterpret_cast<T *>(mem)->~T();
allocated = false; allocated = false;
} }
...@@ -224,334 +202,284 @@ namespace Async { ...@@ -224,334 +202,284 @@ namespace Async {
} }
virtual ~Core() {} virtual ~Core() {}
}; };
template<typename T> template <typename T> struct CoreT : public Core {
struct CoreT : public Core { CoreT() : Core(State::Pending, TypeId::of<T>()), storage() {}
CoreT()
: Core(State::Pending, TypeId::of<T>())
, storage()
{ }
~CoreT() { ~CoreT() {
if (allocated) { if (allocated) {
reinterpret_cast<T*>(&storage)->~T(); reinterpret_cast<T *>(&storage)->~T();
allocated = false; allocated = false;
} }
} }
template<class Other> template <class Other> struct Rebind { typedef CoreT<Other> Type; };
struct Rebind {
typedef CoreT<Other> Type;
};
T& value() { T &value() {
if (state != State::Fulfilled) if (state != State::Fulfilled)
throw Error("Attempted to take the value of a not fulfilled promise"); throw Error("Attempted to take the value of a not fulfilled promise");
return *reinterpret_cast<T*>(&storage); return *reinterpret_cast<T *>(&storage);
} }
bool isVoid() const override { return false; } bool isVoid() const override { return false; }
protected: protected:
void *memory() override { void *memory() override { return &storage; }
return &storage;
}
private: private:
typedef typename std::aligned_storage<sizeof(T), alignof(T)>::type Storage; typedef typename std::aligned_storage<sizeof(T), alignof(T)>::type Storage;
Storage storage; Storage storage;
}; };
template<> template <> struct CoreT<void> : public Core {
struct CoreT<void> : public Core { CoreT() : Core(State::Pending, TypeId::of<void>()) {}
CoreT()
: Core(State::Pending, TypeId::of<void>())
{ }
bool isVoid() const override { return true; } bool isVoid() const override { return true; }
protected: protected:
void *memory() override { void *memory() override { return nullptr; }
return nullptr; };
}
};
template<typename T> template <typename T> struct Continuable : public Request {
struct Continuable : public Request { explicit Continuable(const std::shared_ptr<Core> &chain)
explicit Continuable(const std::shared_ptr<Core>& chain) : resolveCount_(0), rejectCount_(0), chain_(chain) {}
: resolveCount_(0)
, rejectCount_(0)
, chain_(chain)
{ }
void resolve(const std::shared_ptr<Core>& core) override { void resolve(const std::shared_ptr<Core> &core) override {
if (resolveCount_ >= 1) if (resolveCount_ >= 1)
return; //TODO is this the right thing? return; // TODO is this the right thing?
//throw Error("Resolve must not be called more than once"); // throw Error("Resolve must not be called more than once");
++resolveCount_; ++resolveCount_;
doResolve(coreCast(core)); doResolve(coreCast(core));
} }
void reject(const std::shared_ptr<Core>& core) override { void reject(const std::shared_ptr<Core> &core) override {
if (rejectCount_ >= 1) if (rejectCount_ >= 1)
return; //TODO is this the right thing? return; // TODO is this the right thing?
//throw Error("Reject must not be called more than once"); // throw Error("Reject must not be called more than once");
++rejectCount_; ++rejectCount_;
try { try {
doReject(coreCast(core)); doReject(coreCast(core));
} catch (const InternalRethrow& e) { } catch (const InternalRethrow &e) {
chain_->exc = std::move(e.exc); chain_->exc = std::move(e.exc);
chain_->state = State::Rejected; chain_->state = State::Rejected;
for (const auto& req: chain_->requests) { for (const auto &req : chain_->requests) {
req->reject(chain_); req->reject(chain_);
} }
} }
} }
std::shared_ptr<CoreT<T>> coreCast(const std::shared_ptr<Core>& core) const { std::shared_ptr<CoreT<T>> coreCast(const std::shared_ptr<Core> &core) const {
return std::static_pointer_cast<CoreT<T>>(core); return std::static_pointer_cast<CoreT<T>>(core);
} }
virtual void doResolve(const std::shared_ptr<CoreT<T>>& core) = 0; virtual void doResolve(const std::shared_ptr<CoreT<T>> &core) = 0;
virtual void doReject(const std::shared_ptr<CoreT<T>>& core) = 0; virtual void doReject(const std::shared_ptr<CoreT<T>> &core) = 0;
virtual ~Continuable() { } virtual ~Continuable() {}
size_t resolveCount_; size_t resolveCount_;
size_t rejectCount_; size_t rejectCount_;
std::shared_ptr<Core> chain_; std::shared_ptr<Core> chain_;
}; };
namespace impl { namespace impl {
template<typename T, typename Resolve, typename Reject, typename U> struct Continuation; template <typename T, typename Resolve, typename Reject, typename U>
struct Continuation;
template<typename T, typename Resolve, typename Reject, typename Res, typename Cls, typename... Args> template <typename T, typename Resolve, typename Reject, typename Res,
struct Continuation<T, Resolve, Reject, Res (Cls::*)(Args...) const> : public Continuation<T, Resolve, Reject, Res (Args...)> { typename Cls, typename... Args>
typedef Continuation<T, Resolve, Reject, Res (Args...)> Base; 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( Continuation(const std::shared_ptr<Core> &chain, Resolve resolve,
const std::shared_ptr<Core>& chain,
Resolve resolve,
Reject reject) Reject reject)
: Base(chain, std::move(resolve), std::move(reject)) : Base(chain, std::move(resolve), std::move(reject)) {}
{ } };
};
template<typename T, typename Resolve, typename Reject, typename Res, typename Cls, typename... Args> template <typename T, typename Resolve, typename Reject, typename Res,
struct Continuation<T, Resolve, Reject, Res (Cls::*)(Args...)> : public Continuation<T, Resolve, Reject, Res (Args...)> { typename Cls, typename... Args>
typedef Continuation<T, Resolve, Reject, Res (Args...)> Base; struct Continuation<T, Resolve, Reject, Res (Cls::*)(Args...)>
: public Continuation<T, Resolve, Reject, Res(Args...)> {
typedef Continuation<T, Resolve, Reject, Res(Args...)> Base;
Continuation( Continuation(const std::shared_ptr<Core> &chain, Resolve resolve,
const std::shared_ptr<Core>& chain,
Resolve resolve,
Reject reject) Reject reject)
: Base(chain, std::move(resolve), std::move(reject)) : Base(chain, std::move(resolve), std::move(reject)) {}
{ } };
};
// General specialization // General specialization
template<typename T, typename Resolve, typename Reject, typename Res, typename... Args> template <typename T, typename Resolve, typename Reject, typename Res,
struct Continuation<T, Resolve, Reject, Res (Args...)> : public Continuable<T> { typename... Args>
struct Continuation<T, Resolve, Reject, Res(Args...)> : public Continuable<T> {
static_assert(sizeof...(Args) == 1, static_assert(sizeof...(Args) == 1,
"A continuation should only take one single argument"); "A continuation should only take one single argument");
typedef typename detail::nth_element<0, Args...>::type Arg; typedef typename detail::nth_element<0, Args...>::type Arg;
static_assert( static_assert(std::is_same<T, Arg>::value ||
std::is_same<T, Arg>::value ||
std::is_convertible<T, Arg>::value, std::is_convertible<T, Arg>::value,
"Incompatible types detected"); "Incompatible types detected");
Continuation( Continuation(const std::shared_ptr<Core> &chain, Resolve resolve,
const std::shared_ptr<Core>& chain,
Resolve resolve,
Reject reject) Reject reject)
: Continuable<T>(chain) : Continuable<T>(chain), resolve_(resolve), reject_(reject) {}
, resolve_(resolve)
, reject_(reject)
{ }
void doResolve(const std::shared_ptr<CoreT<T>>& core) override { void doResolve(const std::shared_ptr<CoreT<T>> &core) override {
finishResolve(resolve_(detail::tryMove<Resolve>(core->value()))); finishResolve(resolve_(detail::tryMove<Resolve>(core->value())));
} }
void doReject(const std::shared_ptr<CoreT<T>>& core) override { void doReject(const std::shared_ptr<CoreT<T>> &core) override {
reject_(core->exc); reject_(core->exc);
for (const auto& req: this->chain_->requests) { for (const auto &req : this->chain_->requests) {
req->reject(this->chain_); req->reject(this->chain_);
} }
} }
template<typename Ret> template <typename Ret> void finishResolve(Ret &&ret) const {
void finishResolve(Ret&& ret) const {
typedef typename std::decay<Ret>::type CleanRet; typedef typename std::decay<Ret>::type CleanRet;
this->chain_->template construct<CleanRet>(std::forward<Ret>(ret)); this->chain_->template construct<CleanRet>(std::forward<Ret>(ret));
for (const auto& req: this->chain_->requests) { for (const auto &req : this->chain_->requests) {
req->resolve(this->chain_); req->resolve(this->chain_);
} }
} }
Resolve resolve_; Resolve resolve_;
Reject reject_; Reject reject_;
}; };
// Specialization for a void-Promise // Specialization for a void-Promise
template<typename Resolve, typename Reject, typename Res, typename... Args> template <typename Resolve, typename Reject, typename Res, typename... Args>
struct Continuation<void, Resolve, Reject, Res (Args...)> : public Continuable<void> { struct Continuation<void, Resolve, Reject, Res(Args...)>
: public Continuable<void> {
Continuation( Continuation(const std::shared_ptr<Core> &chain, Resolve resolve,
const std::shared_ptr<Core>& chain,
Resolve resolve,
Reject reject) Reject reject)
: Continuable<void>(chain) : Continuable<void>(chain), resolve_(resolve), reject_(reject) {}
, resolve_(resolve)
, reject_(reject)
{ }
static_assert(sizeof...(Args) == 0, static_assert(sizeof...(Args) == 0,
"Can not attach a non-void continuation to a void-Promise"); "Can not attach a non-void continuation to a void-Promise");
void doResolve(const std::shared_ptr<CoreT<void>>& /*core*/) { void doResolve(const std::shared_ptr<CoreT<void>> & /*core*/) {
finishResolve(resolve_()); finishResolve(resolve_());
} }
void doReject(const std::shared_ptr<CoreT<void>>& core) { void doReject(const std::shared_ptr<CoreT<void>> &core) {
reject_(core->exc); reject_(core->exc);
for (const auto& req: this->chain_->requests) { for (const auto &req : this->chain_->requests) {
req->reject(this->chain_); req->reject(this->chain_);
} }
} }
template<typename Ret> template <typename Ret> void finishResolve(Ret &&ret) const {
void finishResolve(Ret&& ret) const {
typedef typename std::remove_reference<Ret>::type CleanRet; typedef typename std::remove_reference<Ret>::type CleanRet;
this->chain_->template construct<CleanRet>(std::forward<Ret>(ret)); this->chain_->template construct<CleanRet>(std::forward<Ret>(ret));
for (const auto& req: this->chain_->requests) { for (const auto &req : this->chain_->requests) {
req->resolve(this->chain_); req->resolve(this->chain_);
} }
} }
Resolve resolve_; Resolve resolve_;
Reject reject_; Reject reject_;
}; };
// Specialization for a callback returning void // Specialization for a callback returning void
template<typename T, typename Resolve, typename Reject, typename... Args> template <typename T, typename Resolve, typename Reject, typename... Args>
struct Continuation<T, Resolve, Reject, void (Args...)> : public Continuable<T> { struct Continuation<T, Resolve, Reject, void(Args...)> : public Continuable<T> {
Continuation( Continuation(const std::shared_ptr<Core> &chain, Resolve resolve,
const std::shared_ptr<Core>& chain,
Resolve resolve,
Reject reject) Reject reject)
: Continuable<T>(chain) : Continuable<T>(chain), resolve_(resolve), reject_(reject) {}
, resolve_(resolve)
, reject_(reject)
{ }
static_assert(sizeof...(Args) == 1, static_assert(sizeof...(Args) == 1,
"A continuation should only take one single argument"); "A continuation should only take one single argument");
typedef typename detail::nth_element<0, Args...>::type Arg; typedef typename detail::nth_element<0, Args...>::type Arg;
static_assert( static_assert(std::is_same<T, Arg>::value ||
std::is_same<T, Arg>::value ||
std::is_convertible<T, Arg>::value, std::is_convertible<T, Arg>::value,
"Incompatible types detected"); "Incompatible types detected");
void doResolve(const std::shared_ptr<CoreT<T>> &core) override {
void doResolve(const std::shared_ptr<CoreT<T>>& core) override {
resolve_(core->value()); resolve_(core->value());
} }
void doReject(const std::shared_ptr<CoreT<T>>& core) override { void doReject(const std::shared_ptr<CoreT<T>> &core) override {
reject_(core->exc); reject_(core->exc);
} }
Resolve resolve_; Resolve resolve_;
Reject reject_; Reject reject_;
}; };
// Specialization for a void-Promise on a callback returning void // Specialization for a void-Promise on a callback returning void
template<typename Resolve, typename Reject, typename... Args> template <typename Resolve, typename Reject, typename... Args>
struct Continuation<void, Resolve, Reject, void (Args...)> : public Continuable<void> { struct Continuation<void, Resolve, Reject, void(Args...)>
: public Continuable<void> {
Continuation( Continuation(const std::shared_ptr<Core> &chain, Resolve resolve,
const std::shared_ptr<Core>& chain,
Resolve resolve,
Reject reject) Reject reject)
: Continuable<void>(chain) : Continuable<void>(chain), resolve_(resolve), reject_(reject) {}
, resolve_(resolve)
, reject_(reject)
{ }
static_assert(sizeof...(Args) == 0, static_assert(sizeof...(Args) == 0,
"Can not attach a non-void continuation to a void-Promise"); "Can not attach a non-void continuation to a void-Promise");
void doResolve(const std::shared_ptr<CoreT<void>>& /*core*/) override { void doResolve(const std::shared_ptr<CoreT<void>> & /*core*/) override {
resolve_(); resolve_();
} }
void doReject(const std::shared_ptr<CoreT<void>>& core) override { void doReject(const std::shared_ptr<CoreT<void>> &core) override {
reject_(core->exc); reject_(core->exc);
} }
Resolve resolve_; Resolve resolve_;
Reject reject_; Reject reject_;
};
}; // Specialization for a callback returning a Promise
template <typename T, typename Resolve, typename Reject, typename U,
// Specialization for a callback returning a Promise typename... Args>
template<typename T, typename Resolve, typename Reject, typename U, typename... Args> struct Continuation<T, Resolve, Reject, Promise<U>(Args...)>
struct Continuation<T, Resolve, Reject, Promise<U> (Args...)> : public Continuable<T> { : public Continuable<T> {
static_assert(sizeof...(Args) == 1, static_assert(sizeof...(Args) == 1,
"A continuation should only take one single argument"); "A continuation should only take one single argument");
typedef typename detail::nth_element<0, Args...>::type Arg; typedef typename detail::nth_element<0, Args...>::type Arg;
static_assert( static_assert(std::is_same<T, Arg>::value ||
std::is_same<T, Arg>::value ||
std::is_convertible<T, Arg>::value, std::is_convertible<T, Arg>::value,
"Incompatible types detected"); "Incompatible types detected");
Continuation( Continuation(const std::shared_ptr<Core> &chain, Resolve resolve,
const std::shared_ptr<Core>& chain,
Resolve resolve,
Reject reject) Reject reject)
: Continuable<T>(chain) : Continuable<T>(chain), resolve_(resolve), reject_(reject) {}
, resolve_(resolve)
, reject_(reject)
{ }
void doResolve(const std::shared_ptr<CoreT<T>>& core) override { void doResolve(const std::shared_ptr<CoreT<T>> &core) override {
auto promise = resolve_(detail::tryMove<Resolve>(core->value())); auto promise = resolve_(detail::tryMove<Resolve>(core->value()));
finishResolve(promise); finishResolve(promise);
} }
void doReject(const std::shared_ptr<CoreT<T>>& core) override { void doReject(const std::shared_ptr<CoreT<T>> &core) override {
reject_(core->exc); reject_(core->exc);
for (const auto& req: core->requests) { for (const auto &req : core->requests) {
req->reject(core); req->reject(core);
} }
} }
template<typename PromiseType> template <typename PromiseType> struct Chainer {
struct Chainer { explicit Chainer(const std::shared_ptr<Private::Core> &core)
explicit Chainer(const std::shared_ptr<Private::Core>& core) : chainCore(core) {}
: chainCore(core)
{ }
void operator()(const PromiseType& val) { void operator()(const PromiseType &val) {
chainCore->construct<PromiseType>(val); chainCore->construct<PromiseType>(val);
for (const auto& req: chainCore->requests) { for (const auto &req : chainCore->requests) {
req->resolve(chainCore); req->resolve(chainCore);
} }
} }
...@@ -559,16 +487,13 @@ namespace Async { ...@@ -559,16 +487,13 @@ namespace Async {
std::shared_ptr<Core> chainCore; std::shared_ptr<Core> chainCore;
}; };
template< template <typename Promise,
typename Promise,
typename Type = typename detail::RemovePromise<Promise>::Type> typename Type = typename detail::RemovePromise<Promise>::Type>
Chainer<Type> Chainer<Type> makeChainer(const Promise &) {
makeChainer(const Promise&) {
return Chainer<Type>(this->chain_); return Chainer<Type>(this->chain_);
} }
template<typename P> template <typename P> void finishResolve(P &promise) {
void finishResolve(P& promise) {
auto chainer = makeChainer(promise); auto chainer = makeChainer(promise);
std::weak_ptr<Core> weakPtr = this->chain_; std::weak_ptr<Core> weakPtr = this->chain_;
promise.then(std::move(chainer), [weakPtr](std::exception_ptr exc) { promise.then(std::move(chainer), [weakPtr](std::exception_ptr exc) {
...@@ -576,56 +501,48 @@ namespace Async { ...@@ -576,56 +501,48 @@ namespace Async {
core->exc = std::move(exc); core->exc = std::move(exc);
core->state = State::Rejected; core->state = State::Rejected;
for (const auto& req: core->requests) { for (const auto &req : core->requests) {
req->reject(core); req->reject(core);
} }
} }
}); });
} }
Resolve resolve_; Resolve resolve_;
Reject reject_; Reject reject_;
};
}; // Specialization for a void callback returning a Promise
template <typename Resolve, typename Reject, typename U, typename... Args>
// Specialization for a void callback returning a Promise struct Continuation<void, Resolve, Reject, Promise<U>(Args...)>
template<typename Resolve, typename Reject, typename U, typename... Args> : public Continuable<void> {
struct Continuation<void, Resolve, Reject, Promise<U> (Args...)> : public Continuable<void> {
static_assert(sizeof...(Args) == 0, static_assert(sizeof...(Args) == 0,
"Can not attach a non-void continuation to a void-Promise"); "Can not attach a non-void continuation to a void-Promise");
Continuation( Continuation(const std::shared_ptr<Core> &chain, Resolve resolve,
const std::shared_ptr<Core>& chain,
Resolve resolve,
Reject reject) Reject reject)
: Continuable<void>(chain) : Continuable<void>(chain), resolve_(resolve), reject_(reject) {}
, resolve_(resolve)
, reject_(reject)
{ }
void doResolve(const std::shared_ptr<CoreT<void>>& /*core*/) { void doResolve(const std::shared_ptr<CoreT<void>> & /*core*/) {
auto promise = resolve_(); auto promise = resolve_();
finishResolve(promise); finishResolve(promise);
} }
void doReject(const std::shared_ptr<CoreT<void>>& core) { void doReject(const std::shared_ptr<CoreT<void>> &core) {
reject_(core->exc); reject_(core->exc);
for (const auto& req: core->requests) { for (const auto &req : core->requests) {
req->reject(core); req->reject(core);
} }
} }
template<typename PromiseType, typename Dummy = void> template <typename PromiseType, typename Dummy = void> struct Chainer {
struct Chainer { explicit Chainer(const std::shared_ptr<Private::Core> &core)
explicit Chainer(const std::shared_ptr<Private::Core>& core) : chainCore(core) {}
: chainCore(core)
{ }
void operator()(const PromiseType& val) { void operator()(const PromiseType &val) {
chainCore->construct<PromiseType>(val); chainCore->construct<PromiseType>(val);
for (const auto& req: chainCore->requests) { for (const auto &req : chainCore->requests) {
req->resolve(chainCore); req->resolve(chainCore);
} }
} }
...@@ -633,17 +550,15 @@ namespace Async { ...@@ -633,17 +550,15 @@ namespace Async {
std::shared_ptr<Core> chainCore; std::shared_ptr<Core> chainCore;
}; };
template<typename Dummy> template <typename Dummy> struct Chainer<void, Dummy> {
struct Chainer<void, Dummy> { explicit Chainer(const std::shared_ptr<Private::Core> &core)
explicit Chainer(const std::shared_ptr<Private::Core>& core) : chainCore(core) {}
: chainCore(core)
{ }
void operator()() { void operator()() {
auto core = this->chain_; auto core = this->chain_;
core->state = State::Fulfilled; core->state = State::Fulfilled;
for (const auto& req: chainCore->requests) { for (const auto &req : chainCore->requests) {
req->resolve(chainCore); req->resolve(chainCore);
} }
} }
...@@ -651,23 +566,20 @@ namespace Async { ...@@ -651,23 +566,20 @@ namespace Async {
std::shared_ptr<Core> chainCore; std::shared_ptr<Core> chainCore;
}; };
template< template <typename Promise,
typename Promise,
typename Type = typename detail::RemovePromise<Promise>::Type> typename Type = typename detail::RemovePromise<Promise>::Type>
Chainer<Type> Chainer<Type> makeChainer(const Promise &) {
makeChainer(const Promise&) {
return Chainer<Type>(this->chain_); return Chainer<Type>(this->chain_);
} }
template<typename P> template <typename P> void finishResolve(P &promise) {
void finishResolve(P& promise) {
auto chainer = makeChainer(promise); auto chainer = makeChainer(promise);
promise.then(std::move(chainer), [=](std::exception_ptr exc) { promise.then(std::move(chainer), [=](std::exception_ptr exc) {
auto core = this->chain_; auto core = this->chain_;
core->exc = std::move(exc); core->exc = std::move(exc);
core->state = State::Rejected; core->state = State::Rejected;
for (const auto& req: core->requests) { for (const auto &req : core->requests) {
req->reject(core); req->reject(core);
} }
}); });
...@@ -675,93 +587,80 @@ namespace Async { ...@@ -675,93 +587,80 @@ namespace Async {
Resolve resolve_; Resolve resolve_;
Reject reject_; Reject reject_;
};
}; } // namespace impl
} // namespace impl
template<typename T, typename Resolve, typename Reject, typename Sig> template <typename T, typename Resolve, typename Reject, typename Sig>
struct Continuation : public impl::Continuation<T, Resolve, Reject, decltype(&Sig::operator())> struct Continuation : public impl::Continuation<T, Resolve, Reject,
{ decltype(&Sig::operator())> {
typedef impl::Continuation<T, Resolve, Reject, decltype(&Sig::operator())> Base; typedef impl::Continuation<T, Resolve, Reject, decltype(&Sig::operator())>
Base;
Continuation( Continuation(const std::shared_ptr<Core> &core, Resolve resolve,
const std::shared_ptr<Core>& core,
Resolve resolve,
Reject reject) Reject reject)
: Base(core, std::move(resolve), std::move(reject)) : Base(core, std::move(resolve), std::move(reject)) {}
{ } };
};
template<typename T, typename Resolve, typename Reject, typename Res, typename... Args> template <typename T, typename Resolve, typename Reject, typename Res,
struct Continuation<T, Resolve, Reject, Res (*)(Args...)> : public impl::Continuation<T, Resolve, Reject, Res (Args...)> typename... Args>
{ struct Continuation<T, Resolve, Reject, Res (*)(Args...)>
typedef impl::Continuation<T, Resolve, Reject, Res (Args...)> Base; : public impl::Continuation<T, Resolve, Reject, Res(Args...)> {
typedef impl::Continuation<T, Resolve, Reject, Res(Args...)> Base;
Continuation( Continuation(const std::shared_ptr<Core> &core, Resolve resolve,
const std::shared_ptr<Core>& core,
Resolve resolve,
Reject reject) Reject reject)
: Base(core, std::move(resolve), std::move(reject)) : Base(core, std::move(resolve), std::move(reject)) {}
{ } };
};
template<typename T, typename Resolve, typename Reject, typename Res, typename Cls, typename... Args> template <typename T, typename Resolve, typename Reject, typename Res,
struct Continuation<T, Resolve, Reject, Res (Cls::*)(Args...)> : public impl::Continuation<T, Resolve, Reject, Res (Args...)> typename Cls, typename... Args>
{ struct Continuation<T, Resolve, Reject, Res (Cls::*)(Args...)>
typedef impl::Continuation<T, Resolve, Reject, Res (Args...)> Base; : public impl::Continuation<T, Resolve, Reject, Res(Args...)> {
typedef impl::Continuation<T, Resolve, Reject, Res(Args...)> Base;
Continuation( Continuation(const std::shared_ptr<Core> &core, Resolve resolve,
const std::shared_ptr<Core>& core,
Resolve resolve,
Reject reject) Reject reject)
: Base(core, std::move(resolve), std::move(reject)) : Base(core, std::move(resolve), std::move(reject)) {}
{ } };
};
template<typename T, typename Resolve, typename Reject, typename Res, typename Cls, typename... Args> template <typename T, typename Resolve, typename Reject, typename Res,
struct Continuation<T, Resolve, Reject, Res (Cls::*)(Args...) const> : public impl::Continuation<T, Resolve, Reject, Res (Args...)> typename Cls, typename... Args>
{ struct Continuation<T, Resolve, Reject, Res (Cls::*)(Args...) const>
typedef impl::Continuation<T, Resolve, Reject, Res (Args...)> Base; : public impl::Continuation<T, Resolve, Reject, Res(Args...)> {
typedef impl::Continuation<T, Resolve, Reject, Res(Args...)> Base;
Continuation( Continuation(const std::shared_ptr<Core> &core, Resolve resolve,
const std::shared_ptr<Core>& core,
Resolve resolve,
Reject reject) Reject reject)
: Base(core, std::move(resolve), std::move(reject)) : Base(core, std::move(resolve), std::move(reject)) {}
{ } };
};
template<typename T, typename Resolve, typename Reject, typename Res, typename... Args> template <typename T, typename Resolve, typename Reject, typename Res,
struct Continuation<T, Resolve, Reject, std::function<Res (Args...)>> : public impl::Continuation<T, Resolve, Reject, Res (Args...)> { typename... Args>
typedef impl::Continuation<T, Resolve, Reject, Res (Args...)> Base; 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( Continuation(const std::shared_ptr<Core> &core, Resolve resolve,
const std::shared_ptr<Core>& core,
Resolve resolve,
Reject reject) Reject reject)
: Base(core, std::move(resolve), std::move(reject)) : Base(core, std::move(resolve), std::move(reject)) {}
{ } };
}; } // namespace Private
}
class Resolver { class Resolver {
public: public:
explicit Resolver(const std::shared_ptr<Private::Core> &core) : core_(core) {}
explicit Resolver(const std::shared_ptr<Private::Core> &core) Resolver(const Resolver &other) = delete;
: core_(core) Resolver &operator=(const Resolver &other) = delete;
{ }
Resolver(const Resolver& other) = delete; Resolver(Resolver &&other) = default;
Resolver& operator=(const Resolver& other) = delete; Resolver &operator=(Resolver &&other) = default;
Resolver(Resolver&& other) = default; template <typename Arg> bool operator()(Arg &&arg) const {
Resolver& operator=(Resolver&& other) = default; if (!core_)
return false;
template<typename Arg>
bool operator()(Arg&& arg) const {
if (!core_) return false;
typedef typename std::remove_reference<Arg>::type Type; typedef typename std::remove_reference<Arg>::type Type;
...@@ -779,7 +678,7 @@ namespace Async { ...@@ -779,7 +678,7 @@ namespace Async {
std::unique_lock<std::mutex> guard(core_->mtx); std::unique_lock<std::mutex> guard(core_->mtx);
core_->construct<Type>(std::forward<Arg>(arg)); core_->construct<Type>(std::forward<Arg>(arg));
for (const auto& req: core_->requests) { for (const auto &req : core_->requests) {
req->resolve(core_); req->resolve(core_);
} }
...@@ -787,7 +686,8 @@ namespace Async { ...@@ -787,7 +686,8 @@ namespace Async {
} }
bool operator()() const { bool operator()() const {
if (!core_) return false; if (!core_)
return false;
if (core_->state != State::Pending) if (core_->state != State::Pending)
throw Error("Attempt to resolve a fulfilled promise"); throw Error("Attempt to resolve a fulfilled promise");
...@@ -797,41 +697,35 @@ namespace Async { ...@@ -797,41 +697,35 @@ namespace Async {
std::unique_lock<std::mutex> guard(core_->mtx); std::unique_lock<std::mutex> guard(core_->mtx);
core_->state = State::Fulfilled; core_->state = State::Fulfilled;
for (const auto& req: core_->requests) { for (const auto &req : core_->requests) {
req->resolve(core_); req->resolve(core_);
} }
return true; return true;
} }
void clear() { void clear() { core_ = nullptr; }
core_ = nullptr;
}
Resolver clone() { Resolver clone() { return Resolver(core_); }
return Resolver(core_);
}
private: private:
std::shared_ptr<Private::Core> core_; std::shared_ptr<Private::Core> core_;
}; };
class Rejection { class Rejection {
public: public:
explicit Rejection(const std::shared_ptr<Private::Core> &core)
: core_(core) {}
explicit Rejection(const std::shared_ptr<Private::Core>& core) Rejection(const Rejection &other) = delete;
: core_(core) Rejection &operator=(const Rejection &other) = delete;
{ }
Rejection(const Rejection& other) = delete; Rejection(Rejection &&other) = default;
Rejection& operator=(const Rejection& other) = delete; Rejection &operator=(Rejection &&other) = default;
Rejection(Rejection&& other) = default; template <typename Exc> bool operator()(Exc exc) const {
Rejection& operator=(Rejection&& other) = default; if (!core_)
return false;
template<typename Exc>
bool operator()(Exc exc) const {
if (!core_) return false;
if (core_->state != State::Pending) if (core_->state != State::Pending)
throw Error("Attempt to reject a fulfilled promise"); throw Error("Attempt to reject a fulfilled promise");
...@@ -839,62 +733,47 @@ namespace Async { ...@@ -839,62 +733,47 @@ namespace Async {
std::unique_lock<std::mutex> guard(core_->mtx); std::unique_lock<std::mutex> guard(core_->mtx);
core_->exc = std::make_exception_ptr(exc); core_->exc = std::make_exception_ptr(exc);
core_->state = State::Rejected; core_->state = State::Rejected;
for (const auto& req: core_->requests) { for (const auto &req : core_->requests) {
req->reject(core_); req->reject(core_);
} }
return true; return true;
} }
void clear() { void clear() { core_ = nullptr; }
core_ = nullptr;
}
Rejection clone() { Rejection clone() { return Rejection(core_); }
return Rejection(core_);
}
private: private:
std::shared_ptr<Private::Core> core_; std::shared_ptr<Private::Core> core_;
};
}; template <typename T> class Deferred {
public:
template<typename T> Deferred() : resolver(nullptr), rejection(nullptr) {}
class Deferred {
public:
Deferred()
: resolver(nullptr)
, rejection(nullptr)
{ }
Deferred(const Deferred& other) = delete; Deferred(const Deferred &other) = delete;
Deferred& operator=(const Deferred& other) = delete; Deferred &operator=(const Deferred &other) = delete;
Deferred(Deferred&& other) = default; Deferred(Deferred &&other) = default;
Deferred& operator=(Deferred&& other) = default; Deferred &operator=(Deferred &&other) = default;
Deferred(Resolver _resolver, Rejection _reject) Deferred(Resolver _resolver, Rejection _reject)
: resolver(std::move(_resolver)) : resolver(std::move(_resolver)), rejection(std::move(_reject)) {}
, rejection(std::move(_reject))
{ }
template<typename U> template <typename U> bool resolve(U &&arg) {
bool resolve(U&& arg) {
typedef typename std::remove_reference<U>::type CleanU; typedef typename std::remove_reference<U>::type CleanU;
static_assert(std::is_same<T, CleanU>::value || std::is_convertible<U, T>::value, static_assert(std::is_same<T, CleanU>::value ||
std::is_convertible<U, T>::value,
"Types mismatch"); "Types mismatch");
return resolver(std::forward<U>(arg)); return resolver(std::forward<U>(arg));
} }
template<typename... Args> template <typename... Args> void emplaceResolve(Args &&...) {}
void emplaceResolve(Args&& ...) {
}
template<typename Exc> template <typename Exc> bool reject(Exc exc) {
bool reject(Exc exc) {
return rejection(std::move(exc)); return rejection(std::move(exc));
} }
...@@ -903,104 +782,81 @@ namespace Async { ...@@ -903,104 +782,81 @@ namespace Async {
rejection.clear(); rejection.clear();
} }
private: private:
Resolver resolver; Resolver resolver;
Rejection rejection; Rejection rejection;
}; };
template<> template <> class Deferred<void> {
class Deferred<void> { public:
public: Deferred() : resolver(nullptr), rejection(nullptr) {}
Deferred() Deferred(const Deferred &other) = delete;
: resolver(nullptr) Deferred &operator=(const Deferred &other) = delete;
, rejection(nullptr)
{ }
Deferred(const Deferred& other) = delete; Deferred(Deferred &&other) = default;
Deferred& operator=(const Deferred& other) = delete; Deferred &operator=(Deferred &&other) = default;
Deferred(Deferred&& other) = default;
Deferred& operator=(Deferred&& other) = default;
Deferred(Resolver _resolver, Rejection _reject) Deferred(Resolver _resolver, Rejection _reject)
: resolver(std::move(_resolver)) : resolver(std::move(_resolver)), rejection(std::move(_reject)) {}
, rejection(std::move(_reject))
{ }
void resolve() { void resolve() { resolver(); }
resolver();
}
template<typename Exc> template <typename Exc> void reject(Exc _exc) { rejection(std::move(_exc)); }
void reject(Exc _exc) {
rejection(std::move(_exc));
}
private: private:
Resolver resolver; Resolver resolver;
Rejection rejection; Rejection rejection;
}; };
static constexpr Private::IgnoreException IgnoreException{}; static constexpr Private::IgnoreException IgnoreException{};
static constexpr Private::NoExcept NoExcept{}; static constexpr Private::NoExcept NoExcept{};
static constexpr Private::Throw Throw{}; static constexpr Private::Throw Throw{};
namespace details { namespace details {
/* /*
* Note that we could use std::result_of to SFINAE-out and dispatch to the right call * Note that we could use std::result_of to SFINAE-out and dispatch to the right
* However, gcc 4.7 does not correctly support std::result_of for SFINAE purposes, so we * call However, gcc 4.7 does not correctly support std::result_of for SFINAE
* use a decltype SFINAE-expression instead. * purposes, so we use a decltype SFINAE-expression instead.
* *
* See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3462.html and * 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 * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56283 for reference
*/ */
template<typename T, typename Func> template <typename T, typename Func>
auto callAsync(Func func, Resolver& resolver, Rejection& rejection) auto callAsync(Func func, Resolver &resolver, Rejection &rejection)
-> decltype(std::declval<Func>()(resolver, rejection), void()) { -> decltype(std::declval<Func>()(resolver, rejection), void()) {
func(resolver, rejection); func(resolver, rejection);
} }
template<typename T, typename Func> template <typename T, typename Func>
auto callAsync(Func func, Resolver& resolver, Rejection& rejection) auto callAsync(Func func, Resolver &resolver, Rejection &rejection)
-> decltype(std::declval<Func>()(Deferred<T>()), void()) { -> decltype(std::declval<Func>()(Deferred<T>()), void()) {
func(Deferred<T>(std::move(resolver), std::move(rejection))); func(Deferred<T>(std::move(resolver), std::move(rejection)));
} }
} } // namespace details
template<typename T> template <typename T> class Promise : public PromiseBase {
class Promise : public PromiseBase public:
{ template <typename U> friend class Promise;
public:
template<typename U> friend class Promise;
typedef Private::CoreT<T> Core; typedef Private::CoreT<T> Core;
template<typename Func> template <typename Func>
explicit Promise(Func func) explicit Promise(Func func)
: core_(std::make_shared<Core>()) : core_(std::make_shared<Core>()), resolver_(core_), rejection_(core_) {
, resolver_(core_)
, rejection_(core_)
{
details::callAsync<T>(func, resolver_, rejection_); details::callAsync<T>(func, resolver_, rejection_);
} }
Promise(const Promise<T>& other) = delete; Promise(const Promise<T> &other) = delete;
Promise& operator=(const Promise<T>& other) = delete; Promise &operator=(const Promise<T> &other) = delete;
Promise(Promise<T>&& other) = default; Promise(Promise<T> &&other) = default;
Promise& operator=(Promise<T>&& other) = default; Promise &operator=(Promise<T> &&other) = default;
virtual ~Promise() virtual ~Promise() {}
{
} template <typename U> static Promise<T> resolved(U &&value) {
template<typename U>
static
Promise<T>
resolved(U&& value) {
static_assert(!std::is_void<T>::value, static_assert(!std::is_void<T>::value,
"Can not resolve a void promise with parameters"); "Can not resolve a void promise with parameters");
static_assert(std::is_same<T, U>::value || std::is_convertible<U, T>::value, static_assert(std::is_same<T, U>::value || std::is_convertible<U, T>::value,
...@@ -1011,9 +867,7 @@ namespace Async { ...@@ -1011,9 +867,7 @@ namespace Async {
return Promise<T>(std::move(core)); return Promise<T>(std::move(core));
} }
static static Promise<void> resolved() {
Promise<void>
resolved() {
static_assert(std::is_void<T>::value, static_assert(std::is_void<T>::value,
"Resolving a non-void promise requires parameters"); "Resolving a non-void promise requires parameters");
...@@ -1022,9 +876,7 @@ namespace Async { ...@@ -1022,9 +876,7 @@ namespace Async {
return Promise<T>(std::move(core)); return Promise<T>(std::move(core));
} }
template<typename Exc> template <typename Exc> static Promise<T> rejected(Exc exc) {
static Promise<T>
rejected(Exc exc) {
auto core = std::make_shared<Core>(); auto core = std::make_shared<Core>();
core->exc = std::make_exception_ptr(exc); core->exc = std::make_exception_ptr(exc);
core->state = State::Rejected; core->state = State::Rejected;
...@@ -1035,30 +887,25 @@ namespace Async { ...@@ -1035,30 +887,25 @@ namespace Async {
bool isFulfilled() const override { return core_->state == State::Fulfilled; } bool isFulfilled() const override { return core_->state == State::Fulfilled; }
bool isRejected() const override { return core_->state == State::Rejected; } bool isRejected() const override { return core_->state == State::Rejected; }
template<typename ResolveFunc, typename RejectFunc> template <typename ResolveFunc, typename RejectFunc>
auto auto then(ResolveFunc resolveFunc, RejectFunc rejectFunc)
then(ResolveFunc resolveFunc, RejectFunc rejectFunc) -> Promise<typename detail::RemovePromise<
-> Promise< typename detail::FunctionTrait<ResolveFunc>::ReturnType>::Type> {
typename detail::RemovePromise<
typename detail::FunctionTrait<ResolveFunc>::ReturnType
>::Type
>
{
typedef typename detail::RemovePromise< typedef typename detail::RemovePromise<
typename detail::FunctionTrait<ResolveFunc>::ReturnType typename detail::FunctionTrait<ResolveFunc>::ReturnType>::Type RetType;
>::Type RetType;
Promise<RetType> promise; Promise<RetType> promise;
typedef Private::Continuation<T, ResolveFunc, RejectFunc, ResolveFunc> Continuation; typedef Private::Continuation<T, ResolveFunc, RejectFunc, ResolveFunc>
std::shared_ptr<Private::Request> req = std::make_shared<Continuation>(promise.core_, resolveFunc, rejectFunc); Continuation;
std::shared_ptr<Private::Request> req =
std::make_shared<Continuation>(promise.core_, resolveFunc, rejectFunc);
std::unique_lock<std::mutex> guard(core_->mtx); std::unique_lock<std::mutex> guard(core_->mtx);
if (isFulfilled()) { if (isFulfilled()) {
req->resolve(core_); req->resolve(core_);
} } else if (isRejected()) {
else if (isRejected()) {
req->reject(core_); req->reject(core_);
} }
...@@ -1067,55 +914,52 @@ namespace Async { ...@@ -1067,55 +914,52 @@ namespace Async {
return promise; return promise;
} }
private: private:
Promise() Promise()
: core_(std::make_shared<Core>()) : core_(std::make_shared<Core>()), resolver_(core_), rejection_(core_) {}
, resolver_(core_)
, rejection_(core_)
{
}
explicit Promise(std::shared_ptr<Core>&& core) explicit Promise(std::shared_ptr<Core> &&core)
: core_(core) : core_(core), resolver_(core_), rejection_(core_) {}
, resolver_(core_)
, rejection_(core_)
{ }
std::shared_ptr<Core> core_; std::shared_ptr<Core> core_;
Resolver resolver_; Resolver resolver_;
Rejection rejection_; Rejection rejection_;
}; };
template<typename T> template <typename T> class Barrier {
class Barrier { public:
public: explicit Barrier(Promise<T> &promise) : promise_(promise) {}
explicit Barrier(Promise<T>& promise)
: promise_(promise) {
}
void wait() { void wait() {
if (promise_.isFulfilled() || promise_.isRejected()) return; if (promise_.isFulfilled() || promise_.isRejected())
return;
promise_.then([&](const T&) mutable { promise_.then(
[&](const T &) mutable {
std::unique_lock<std::mutex> guard(mtx); std::unique_lock<std::mutex> guard(mtx);
cv.notify_one(); cv.notify_one();
}, [&](std::exception_ptr) mutable { },
[&](std::exception_ptr) mutable {
std::unique_lock<std::mutex> guard(mtx); std::unique_lock<std::mutex> guard(mtx);
cv.notify_one(); cv.notify_one();
}); });
std::unique_lock<std::mutex> guard(mtx); std::unique_lock<std::mutex> guard(mtx);
cv.wait(guard, [&] { return promise_.isFulfilled() || promise_.isRejected(); }); cv.wait(guard,
[&] { return promise_.isFulfilled() || promise_.isRejected(); });
} }
template<class Rep, class Period> template <class Rep, class Period>
std::cv_status wait_for(const std::chrono::duration<Rep, Period>& 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 (promise_.isFulfilled() || promise_.isRejected())
return std::cv_status::no_timeout;
promise_.then([&](const T&) mutable { promise_.then(
[&](const T &) mutable {
std::unique_lock<std::mutex> guard(mtx); std::unique_lock<std::mutex> guard(mtx);
cv.notify_one(); cv.notify_one();
}, [&](std::exception_ptr) mutable { },
[&](std::exception_ptr) mutable {
std::unique_lock<std::mutex> guard(mtx); std::unique_lock<std::mutex> guard(mtx);
cv.notify_one(); cv.notify_one();
}); });
...@@ -1124,64 +968,54 @@ namespace Async { ...@@ -1124,64 +968,54 @@ namespace Async {
return cv.wait_for(guard, period); return cv.wait_for(guard, period);
} }
private: private:
Promise<T>& promise_; Promise<T> &promise_;
mutable std::mutex mtx; mutable std::mutex mtx;
std::condition_variable cv; std::condition_variable cv;
}; };
namespace Impl { namespace Impl {
struct Any; struct Any;
} }
class Any { class Any {
public: public:
friend struct Impl::Any; friend struct Impl::Any;
Any(const Any& other) = default; Any(const Any &other) = default;
Any& operator=(const Any& other) = default; Any &operator=(const Any &other) = default;
Any(Any&& other) = default; Any(Any &&other) = default;
Any& operator=(Any&& other) = default; Any &operator=(Any &&other) = default;
template<typename T> template <typename T> bool is() const { return core_->id == TypeId::of<T>(); }
bool is() const {
return core_->id == TypeId::of<T>();
}
template<typename T> template <typename T> T cast() const {
T cast() const { if (!is<T>())
if (!is<T>()) throw BadAnyCast(); throw BadAnyCast();
auto core = std::static_pointer_cast<Private::CoreT<T>>(core_); auto core = std::static_pointer_cast<Private::CoreT<T>>(core_);
return core->value(); return core->value();
} }
private: private:
explicit Any(const std::shared_ptr<Private::Core>& core) explicit Any(const std::shared_ptr<Private::Core> &core) : core_(core) {}
: core_(core)
{ }
std::shared_ptr<Private::Core> core_; std::shared_ptr<Private::Core> core_;
};
}; namespace Impl {
namespace Impl {
/* Instead of duplicating the code between whenAll and whenAny functions, the main implementation /* Instead of duplicating the code between whenAll and whenAny functions, the
* is in the When class below and we configure the class with a policy instead, depending if we * main implementation is in the When class below and we configure the class
* are executing an "all" or "any" operation, how cool is that ? * with a policy instead, depending if we are executing an "all" or "any"
* operation, how cool is that ?
*/ */
struct All { struct All {
struct Data { struct Data {
Data(const size_t _total, Resolver _resolver, Rejection _rejection) Data(const size_t _total, Resolver _resolver, Rejection _rejection)
: total(_total) : total(_total), resolved(0), rejected(false), mtx(),
, resolved(0) resolve(std::move(_resolver)), reject(std::move(_rejection)) {}
, rejected(false)
, mtx()
, resolve(std::move(_resolver))
, reject(std::move(_rejection))
{ }
const size_t total; const size_t total;
size_t resolved; size_t resolved;
...@@ -1192,11 +1026,12 @@ namespace Async { ...@@ -1192,11 +1026,12 @@ namespace Async {
Rejection reject; Rejection reject;
}; };
template<size_t Index, typename T, typename Data> template <size_t Index, typename T, typename Data>
static void resolveT(const T& val, Data& data) { static void resolveT(const T &val, Data &data) {
std::lock_guard<std::mutex> guard(data->mtx); std::lock_guard<std::mutex> guard(data->mtx);
if (data->rejected) return; if (data->rejected)
return;
// @Check thread-safety of std::get ? // @Check thread-safety of std::get ?
std::get<Index>(data->results) = val; std::get<Index>(data->results) = val;
...@@ -1207,11 +1042,11 @@ namespace Async { ...@@ -1207,11 +1042,11 @@ namespace Async {
} }
} }
template<typename Data> template <typename Data> static void resolveVoid(Data &data) {
static void resolveVoid(Data& data) {
std::lock_guard<std::mutex> guard(data->mtx); std::lock_guard<std::mutex> guard(data->mtx);
if (data->rejected) return; if (data->rejected)
return;
data->resolved++; data->resolved++;
...@@ -1220,24 +1055,21 @@ namespace Async { ...@@ -1220,24 +1055,21 @@ namespace Async {
} }
} }
template<typename Data> template <typename Data>
static void reject(std::exception_ptr exc, Data& data) { static void reject(std::exception_ptr exc, Data &data) {
std::lock_guard<std::mutex> guard(data->mtx); std::lock_guard<std::mutex> guard(data->mtx);
data->rejected = true; data->rejected = true;
data->reject(exc); data->reject(exc);
} }
}; };
struct Any { struct Any {
struct Data { struct Data {
Data(size_t, Resolver resolver, Rejection rejection) Data(size_t, Resolver resolver, Rejection rejection)
: done(false) : done(false), mtx(), resolve(std::move(resolver)),
, mtx() reject(std::move(rejection)) {}
, resolve(std::move(resolver))
, reject(std::move(rejection))
{ }
bool done; bool done;
std::mutex mtx; std::mutex mtx;
...@@ -1246,14 +1078,16 @@ namespace Async { ...@@ -1246,14 +1078,16 @@ namespace Async {
Rejection reject; Rejection reject;
}; };
template<size_t Index, typename T, typename Data> template <size_t Index, typename T, typename Data>
static void resolveT(const T& val, Data& data) { static void resolveT(const T &val, Data &data) {
std::lock_guard<std::mutex> guard(data->mtx); std::lock_guard<std::mutex> guard(data->mtx);
if (data->done) return; if (data->done)
return;
// Instead of allocating a new core, ideally we could share the same core as // 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 // the relevant promise but we do not have access to the promise here is so
// meh
auto core = std::make_shared<Private::CoreT<T>>(); auto core = std::make_shared<Private::CoreT<T>>();
core->template construct<T>(val); core->template construct<T>(val);
data->resolve(Async::Any(core)); data->resolve(Async::Any(core));
...@@ -1261,11 +1095,11 @@ namespace Async { ...@@ -1261,11 +1095,11 @@ namespace Async {
data->done = true; data->done = true;
} }
template<typename Data> template <typename Data> static void resolveVoid(Data &data) {
static void resolveVoid(Data& data) {
std::lock_guard<std::mutex> guard(data->mtx); std::lock_guard<std::mutex> guard(data->mtx);
if (data->done) return; if (data->done)
return;
auto core = std::make_shared<Private::CoreT<void>>(); auto core = std::make_shared<Private::CoreT<void>>();
data->resolve(Async::Any(core)); data->resolve(Async::Any(core));
...@@ -1273,139 +1107,114 @@ namespace Async { ...@@ -1273,139 +1107,114 @@ namespace Async {
data->done = true; data->done = true;
} }
template<typename Data> template <typename Data>
static void reject(std::exception_ptr exc, Data& data) { static void reject(std::exception_ptr exc, Data &data) {
std::lock_guard<std::mutex> guard(data->mtx); std::lock_guard<std::mutex> guard(data->mtx);
data->done = true; data->done = true;
data->reject(exc); data->reject(exc);
} }
}; };
template<typename ContinuationPolicy> template <typename ContinuationPolicy> struct When {
struct When {
When(Resolver resolver, Rejection rejection) When(Resolver resolver, Rejection rejection)
: resolve(std::move(resolver)) : resolve(std::move(resolver)), reject(std::move(rejection)) {}
, reject(std::move(rejection))
{ }
template<typename... Args> template <typename... Args> void operator()(Args &&... args) {
void operator()(Args&&... args) {
whenArgs(std::forward<Args>(args)...); whenArgs(std::forward<Args>(args)...);
} }
private: private:
template<typename T, size_t Index, typename Data> template <typename T, size_t Index, typename Data> struct WhenContinuation {
struct WhenContinuation { explicit WhenContinuation(Data _data) : data(std::move(_data)) {}
explicit WhenContinuation(Data _data)
: data(std::move(_data))
{ }
void operator()(const T& val) const { void operator()(const T &val) const {
ContinuationPolicy::template resolveT<Index>(val, data); ContinuationPolicy::template resolveT<Index>(val, data);
} }
Data data; Data data;
}; };
template<size_t Index, typename Data> template <size_t Index, typename Data>
struct WhenContinuation<void, Index, Data> { struct WhenContinuation<void, Index, Data> {
explicit WhenContinuation(Data _data) explicit WhenContinuation(Data _data) : data(std::move(_data)) {}
: data(std::move(_data))
{ }
void operator()() const { void operator()() const { ContinuationPolicy::resolveVoid(data); }
ContinuationPolicy::resolveVoid(data);
}
Data data; Data data;
}; };
template<typename T, size_t Index, typename Data> template <typename T, size_t Index, typename Data>
WhenContinuation<T, Index, Data> WhenContinuation<T, Index, Data> makeContinuation(const Data &data) {
makeContinuation(const Data& data) {
return WhenContinuation<T, Index, Data>(data); return WhenContinuation<T, Index, Data>(data);
} }
template<size_t Index, typename Data, typename T> template <size_t Index, typename Data, typename T>
void when(const Data& data, Promise<T>& promise) { void when(const Data &data, Promise<T> &promise) {
promise.then(makeContinuation<T, Index>(data), [=](std::exception_ptr ptr) { promise.then(makeContinuation<T, Index>(data), [=](std::exception_ptr ptr) {
ContinuationPolicy::reject(std::move(ptr), data); ContinuationPolicy::reject(std::move(ptr), data);
}); });
} }
template<size_t Index, typename Data, typename T> template <size_t Index, typename Data, typename T>
void when(const Data& data, T&& arg) { void when(const Data &data, T &&arg) {
typedef typename std::remove_reference<T>::type CleanT; typedef typename std::remove_reference<T>::type CleanT;
auto promise = Promise<CleanT>::resolved(std::forward<T>(arg)); auto promise = Promise<CleanT>::resolved(std::forward<T>(arg));
when<Index>(data, promise); when<Index>(data, promise);
} }
template<typename... Args> template <typename... Args> void whenArgs(Args &&... args) {
void whenArgs(Args&& ...args) { typedef std::tuple<typename detail::RemovePromise<
typedef std::tuple< typename std::remove_reference<Args>::type>::Type...>
typename detail::RemovePromise< Results;
typename std::remove_reference<Args>::type
>::Type...
> Results;
/* We need to keep the results alive until the last promise /* We need to keep the results alive until the last promise
* finishes its execution * finishes its execution
*/ */
/* See the trick here ? Basically, we only have access to the real type of the results /* See the trick here ? Basically, we only have access to the real type of
* in this function. The policy classes do not have access to the full type (std::tuple), * the results in this function. The policy classes do not have access to
* but, instead, take a generic template data type as a parameter. They only need to know * the full type (std::tuple), but, instead, take a generic template data
* that results is a tuple, they do not need to know the real type of the results. * 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 * This is some sort of compile-time template type-erasing, hue
*/ */
struct Data : public ContinuationPolicy::Data { struct Data : public ContinuationPolicy::Data {
Data(size_t total, Resolver resolver, Rejection rejection) Data(size_t total, Resolver resolver, Rejection rejection)
: ContinuationPolicy::Data(total, std::move(resolver), std::move(rejection)) : ContinuationPolicy::Data(total, std::move(resolver),
{ } std::move(rejection)) {}
Results results; Results results;
}; };
auto data = std::make_shared<Data>(sizeof...(Args), std::move(resolve), std::move(reject)); auto data = std::make_shared<Data>(sizeof...(Args), std::move(resolve),
std::move(reject));
whenArgs<0>(data, std::forward<Args>(args)...); whenArgs<0>(data, std::forward<Args>(args)...);
} }
template<size_t Index, typename Data, typename Head, typename... Rest> template <size_t Index, typename Data, typename Head, typename... Rest>
void whenArgs(const Data& data, Head&& head, Rest&& ...rest) { void whenArgs(const Data &data, Head &&head, Rest &&... rest) {
when<Index>(data, std::forward<Head>(head)); when<Index>(data, std::forward<Head>(head));
whenArgs<Index + 1>(data, std::forward<Rest>(rest)...); whenArgs<Index + 1>(data, std::forward<Rest>(rest)...);
} }
template<size_t Index, typename Data, typename Head> template <size_t Index, typename Data, typename Head>
void whenArgs(const Data& data, Head&& head) { void whenArgs(const Data &data, Head &&head) {
when<Index>(data, std::forward<Head>(head)); when<Index>(data, std::forward<Head>(head));
} }
Resolver resolve; Resolver resolve;
Rejection reject; Rejection reject;
}; };
template< template <typename T, typename Results> struct WhenAllRange {
typename T,
typename Results
>
struct WhenAllRange
{
WhenAllRange(Resolver _resolve, Rejection _reject) WhenAllRange(Resolver _resolve, Rejection _reject)
: resolve(std::move(_resolve)) : resolve(std::move(_resolve)), reject(std::move(_reject)) {}
, reject(std::move(_reject))
{ }
template<typename Iterator> template <typename Iterator> void operator()(Iterator first, Iterator last) {
void operator()(Iterator first, Iterator last)
{
auto data = std::make_shared<DataT<T>>( auto data = std::make_shared<DataT<T>>(
static_cast<size_t>(std::distance(first, last)), static_cast<size_t>(std::distance(first, last)), std::move(resolve),
std::move(resolve), std::move(reject));
std::move(reject)
);
size_t index = 0; size_t index = 0;
for (auto it = first; it != last; ++it) { for (auto it = first; it != last; ++it) {
...@@ -1415,7 +1224,8 @@ namespace Async { ...@@ -1415,7 +1224,8 @@ namespace Async {
it->then(std::move(cont), [=](std::exception_ptr ptr) { it->then(std::move(cont), [=](std::exception_ptr ptr) {
std::lock_guard<std::mutex> guard(data->mtx); std::lock_guard<std::mutex> guard(data->mtx);
if (data->rejected) return; if (data->rejected)
return;
data->rejected = true; data->rejected = true;
data->reject(std::move(ptr)); data->reject(std::move(ptr));
...@@ -1425,17 +1235,11 @@ namespace Async { ...@@ -1425,17 +1235,11 @@ namespace Async {
} }
} }
private: private:
struct Data struct Data {
{
Data(size_t _total, Resolver _resolver, Rejection _rejection) Data(size_t _total, Resolver _resolver, Rejection _rejection)
: total(_total) : total(_total), resolved(0), rejected(false), mtx(),
, resolved(0) resolve(std::move(_resolver)), reject(std::move(_rejection)) {}
, rejected(false)
, mtx()
, resolve(std::move(_resolver))
, reject(std::move(_rejection))
{ }
const size_t total; const size_t total;
size_t resolved; size_t resolved;
...@@ -1450,10 +1254,10 @@ namespace Async { ...@@ -1450,10 +1254,10 @@ namespace Async {
* here, so you know what, compiler ? Take that Dummy type and leave * here, so you know what, compiler ? Take that Dummy type and leave
* me alone * me alone
*/ */
template<typename ValueType, typename Dummy = void> struct DataT : public Data { template <typename ValueType, typename Dummy = void>
struct DataT : public Data {
DataT(size_t total, Resolver resolver, Rejection rejection) DataT(size_t total, Resolver resolver, Rejection rejection)
: Data(total, std::move(resolver), std::move(rejection)) : Data(total, std::move(resolver), std::move(rejection)) {
{
results.resize(total); results.resize(total);
} }
...@@ -1463,33 +1267,26 @@ namespace Async { ...@@ -1463,33 +1267,26 @@ namespace Async {
/* For a vector of void promises, we do not have any results, that's /* For a vector of void promises, we do not have any results, that's
* why we need a distinct specialization for the void case * why we need a distinct specialization for the void case
*/ */
template<typename Dummy> struct DataT<void, Dummy> : public Data { template <typename Dummy> struct DataT<void, Dummy> : public Data {
DataT(size_t total, Resolver resolver, Rejection rejection) DataT(size_t total, Resolver resolver, Rejection rejection)
: Data(total, std::move(resolver), std::move(rejection)) : Data(total, std::move(resolver), std::move(rejection)) {}
{
}
}; };
template<typename ValueType, typename Dummy = void> template <typename ValueType, typename Dummy = void> struct WhenContinuation {
struct WhenContinuation
{
using D = std::shared_ptr<DataT<ValueType>>; using D = std::shared_ptr<DataT<ValueType>>;
WhenContinuation(const D& _data, size_t _index) WhenContinuation(const D &_data, size_t _index)
: data(_data) : data(_data), index(_index) {}
, index(_index)
{ }
void operator()(const ValueType& val) const void operator()(const ValueType &val) const {
{
std::lock_guard<std::mutex> guard(data->mtx); std::lock_guard<std::mutex> guard(data->mtx);
if (data->rejected) return; if (data->rejected)
return;
data->results[index] = val; data->results[index] = val;
data->resolved++; data->resolved++;
if (data->resolved == data->total) if (data->resolved == data->total) {
{
data->resolve(data->results); data->resolve(data->results);
} }
} }
...@@ -1498,24 +1295,19 @@ namespace Async { ...@@ -1498,24 +1295,19 @@ namespace Async {
size_t index; size_t index;
}; };
template<typename Dummy> template <typename Dummy> struct WhenContinuation<void, Dummy> {
struct WhenContinuation<void, Dummy>
{
using D = std::shared_ptr<DataT<void>>; using D = std::shared_ptr<DataT<void>>;
WhenContinuation(const D& _data, size_t) WhenContinuation(const D &_data, size_t) : data(_data) {}
: data(_data)
{ }
void operator()() const void operator()() const {
{
std::lock_guard<std::mutex> guard(data->mtx); std::lock_guard<std::mutex> guard(data->mtx);
if (data->rejected) return; if (data->rejected)
return;
data->resolved++; data->resolved++;
if (data->resolved == data->total) if (data->resolved == data->total) {
{
data->resolve(); data->resolve();
} }
} }
...@@ -1525,27 +1317,21 @@ namespace Async { ...@@ -1525,27 +1317,21 @@ namespace Async {
Resolver resolve; Resolver resolve;
Rejection reject; Rejection reject;
}; };
} } // namespace Impl
template< template <typename... Args,
typename... Args, typename Results = std::tuple<typename detail::RemovePromise<
typename Results = typename std::remove_reference<Args>::type>::Type...>>
std::tuple< Promise<Results> whenAll(Args &&... args) {
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 // 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 // whereby template parameters pack inside a lambda expression are not
// captured correctly and can not be expanded inside the lambda. // captured correctly and can not be expanded inside the lambda.
Resolver* resolve; Resolver *resolve;
Rejection* reject; Rejection *reject;
Promise<Results> promise([&](Resolver& resolver, Rejection& rejection) { Promise<Results> promise([&](Resolver &resolver, Rejection &rejection) {
resolve = &resolver; resolve = &resolver;
reject = &rejection; reject = &rejection;
}); });
...@@ -1556,15 +1342,14 @@ namespace Async { ...@@ -1556,15 +1342,14 @@ namespace Async {
impl(std::forward<Args>(args)...); impl(std::forward<Args>(args)...);
return promise; return promise;
} }
template<typename... Args> template <typename... Args> Promise<Any> whenAny(Args &&... args) {
Promise<Any> whenAny(Args&& ...args) {
// Same trick as above; // Same trick as above;
Resolver* resolve; Resolver *resolve;
Rejection* reject; Rejection *reject;
Promise<Any> promise([&](Resolver& resolver, Rejection& rejection) { Promise<Any> promise([&](Resolver &resolver, Rejection &rejection) {
resolve = &resolver; resolve = &resolver;
reject = &rejection; reject = &rejection;
}); });
...@@ -1572,32 +1357,24 @@ namespace Async { ...@@ -1572,32 +1357,24 @@ namespace Async {
Impl::When<Impl::Any> impl(std::move(*resolve), std::move(*reject)); Impl::When<Impl::Any> impl(std::move(*resolve), std::move(*reject));
impl(std::forward<Args>(args)...); impl(std::forward<Args>(args)...);
return promise; return promise;
} }
template< template <typename Iterator,
typename Iterator, typename ValueType = typename detail::RemovePromise<
typename ValueType typename std::iterator_traits<Iterator>::value_type>::Type,
= typename detail::RemovePromise< typename Results =
typename std::iterator_traits<Iterator>::value_type typename std::conditional<std::is_same<void, ValueType>::value,
>::Type, void, std::vector<ValueType>>::type>
typename Results Promise<Results> whenAll(Iterator first, Iterator last) {
= 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 */ /* @Security, assert that last >= first */
return Promise<Results>([=](Resolver& resolve, Rejection& rejection) { return Promise<Results>([=](Resolver &resolve, Rejection &rejection) {
Impl::WhenAllRange<ValueType, Results> impl(std::move(resolve),
Impl::WhenAllRange<ValueType, Results> impl( std::move(rejection));
std::move(resolve), std::move(rejection));
impl(first, last); impl(first, last);
}); });
} }
} // namespace Async } // namespace Async
} // namespace Pistache } // namespace Pistache
...@@ -255,7 +255,8 @@ public: ...@@ -255,7 +255,8 @@ public:
*/ */
explicit RouterHandler(std::shared_ptr<Rest::Router> router); 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: private:
std::shared_ptr<Tcp::Handler> clone() const final { std::shared_ptr<Tcp::Handler> clone() const final {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment