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 @@
#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:
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 does not match)"),
id_(std::move(id)) {}
TypeId typeId() const {
return id_;
}
TypeId typeId() const { return id_; }
private:
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() { }
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(); }
};
};
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) {
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 Func>
struct FunctionTrait : public FunctionTrait<decltype(&Func::operator())> {};
template<typename R, typename Class, typename... Args>
struct FunctionTrait<R (Class::*)(Args...) const> {
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...)> {
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 { typedef T Type; };
template<typename T>
struct RemovePromise<Promise<T>> {
typedef T Type;
};
template <typename T> 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>
struct nth_element<0, Head, Tail...> {
template <typename Head, typename... Tail>
struct nth_element<0, Head, Tail...> {
typedef Head type;
};
};
template<size_t N, typename Head, typename... Tail>
struct nth_element<N, Head, Tail...> {
template <size_t N, typename Head, typename... Tail>
struct nth_element<N, Head, Tail...> {
typedef typename nth_element<N - 1, Tail...>::type type;
};
};
}
} // namespace detail
namespace Private {
namespace Private {
struct InternalRethrow {
explicit InternalRethrow(std::exception_ptr _exc)
: exc(std::move(_exc))
{ }
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 IgnoreException {
void operator()(std::exception_ptr) const {}
};
struct NoExcept {
struct NoExcept {
void operator()(std::exception_ptr) const { std::terminate(); }
};
};
struct Throw {
struct Throw {
void operator()(std::exception_ptr exc) const {
throw InternalRethrow(std::move(exc));
}
};
};
struct Core;
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;
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 {
struct Core {
Core(State _state, TypeId _id)
: allocated(false)
, state(_state)
, exc()
, mtx()
, requests()
, id(_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.
* 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
* 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 void *memory() = 0;
virtual bool isVoid() const = 0;
template<typename T, typename... Args>
void construct(Args&&... args) {
template <typename T, typename... Args> void construct(Args &&... args) {
if (isVoid())
throw Error("Can not construct a void core");
......@@ -214,7 +192,7 @@ namespace Async {
void *mem = memory();
if (allocated) {
reinterpret_cast<T*>(mem)->~T();
reinterpret_cast<T *>(mem)->~T();
allocated = false;
}
......@@ -224,334 +202,284 @@ namespace Async {
}
virtual ~Core() {}
};
};
template<typename T>
struct CoreT : public Core {
CoreT()
: Core(State::Pending, TypeId::of<T>())
, storage()
{ }
template <typename T> struct CoreT : public Core {
CoreT() : Core(State::Pending, TypeId::of<T>()), storage() {}
~CoreT() {
if (allocated) {
reinterpret_cast<T*>(&storage)->~T();
reinterpret_cast<T *>(&storage)->~T();
allocated = false;
}
}
template<class Other>
struct Rebind {
typedef CoreT<Other> Type;
};
template <class Other> struct Rebind { typedef CoreT<Other> Type; };
T& value() {
T &value() {
if (state != State::Fulfilled)
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; }
protected:
void *memory() override {
return &storage;
}
protected:
void *memory() override { return &storage; }
private:
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>())
{ }
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;
}
};
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)
{ }
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 {
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; // 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 {
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");
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) {
} catch (const InternalRethrow &e) {
chain_->exc = std::move(e.exc);
chain_->state = State::Rejected;
for (const auto& req: chain_->requests) {
for (const auto &req : chain_->requests) {
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);
}
virtual void doResolve(const std::shared_ptr<CoreT<T>>& core) = 0;
virtual void doReject(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 ~Continuable() { }
virtual ~Continuable() {}
size_t resolveCount_;
size_t rejectCount_;
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>
struct Continuation<T, Resolve, Reject, Res (Cls::*)(Args...) const> : public Continuation<T, Resolve, Reject, Res (Args...)> {
typedef Continuation<T, Resolve, Reject, Res (Args...)> Base;
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,
Continuation(const std::shared_ptr<Core> &chain, Resolve resolve,
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>
struct Continuation<T, Resolve, Reject, Res (Cls::*)(Args...)> : public Continuation<T, Resolve, Reject, Res (Args...)> {
typedef Continuation<T, Resolve, Reject, Res (Args...)> Base;
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,
Continuation(const std::shared_ptr<Core> &chain, Resolve resolve,
Reject reject)
: Base(chain, std::move(resolve), std::move(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> {
// 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 ||
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,
Continuation(const std::shared_ptr<Core> &chain, Resolve resolve,
Reject reject)
: Continuable<T>(chain)
, resolve_(resolve)
, reject_(reject)
{ }
: Continuable<T>(chain), 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())));
}
void doReject(const std::shared_ptr<CoreT<T>>& core) override {
void doReject(const std::shared_ptr<CoreT<T>> &core) override {
reject_(core->exc);
for (const auto& req: this->chain_->requests) {
for (const auto &req : this->chain_->requests) {
req->reject(this->chain_);
}
}
template<typename Ret>
void finishResolve(Ret&& ret) const {
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) {
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> {
// 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,
Continuation(const std::shared_ptr<Core> &chain, Resolve resolve,
Reject reject)
: Continuable<void>(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*/) {
void doResolve(const std::shared_ptr<CoreT<void>> & /*core*/) {
finishResolve(resolve_());
}
void doReject(const std::shared_ptr<CoreT<void>>& core) {
void doReject(const std::shared_ptr<CoreT<void>> &core) {
reject_(core->exc);
for (const auto& req: this->chain_->requests) {
for (const auto &req : this->chain_->requests) {
req->reject(this->chain_);
}
}
template<typename Ret>
void finishResolve(Ret&& ret) const {
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) {
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> {
// 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,
Continuation(const std::shared_ptr<Core> &chain, Resolve resolve,
Reject reject)
: Continuable<T>(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 ||
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 {
void doResolve(const std::shared_ptr<CoreT<T>> &core) override {
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);
}
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> {
// 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,
Continuation(const std::shared_ptr<Core> &chain, Resolve resolve,
Reject reject)
: Continuable<void>(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 {
void doResolve(const std::shared_ptr<CoreT<void>> & /*core*/) override {
resolve_();
}
void doReject(const std::shared_ptr<CoreT<void>>& core) override {
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> {
// 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 ||
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,
Continuation(const std::shared_ptr<Core> &chain, Resolve resolve,
Reject reject)
: Continuable<T>(chain)
, resolve_(resolve)
, reject_(reject)
{ }
: Continuable<T>(chain), 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()));
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);
for (const auto& req: core->requests) {
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)
{ }
template <typename PromiseType> struct Chainer {
explicit Chainer(const std::shared_ptr<Private::Core> &core)
: chainCore(core) {}
void operator()(const PromiseType& val) {
void operator()(const PromiseType &val) {
chainCore->construct<PromiseType>(val);
for (const auto& req: chainCore->requests) {
for (const auto &req : chainCore->requests) {
req->resolve(chainCore);
}
}
......@@ -559,16 +487,13 @@ namespace Async {
std::shared_ptr<Core> chainCore;
};
template<
typename Promise,
template <typename Promise,
typename Type = typename detail::RemovePromise<Promise>::Type>
Chainer<Type>
makeChainer(const Promise&) {
Chainer<Type> makeChainer(const Promise &) {
return Chainer<Type>(this->chain_);
}
template<typename P>
void finishResolve(P& promise) {
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) {
......@@ -576,56 +501,48 @@ namespace Async {
core->exc = std::move(exc);
core->state = State::Rejected;
for (const auto& req: core->requests) {
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> {
// 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,
Continuation(const std::shared_ptr<Core> &chain, Resolve resolve,
Reject reject)
: Continuable<void>(chain)
, resolve_(resolve)
, reject_(reject)
{ }
: Continuable<void>(chain), 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_();
finishResolve(promise);
}
void doReject(const std::shared_ptr<CoreT<void>>& core) {
void doReject(const std::shared_ptr<CoreT<void>> &core) {
reject_(core->exc);
for (const auto& req: core->requests) {
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)
{ }
template <typename PromiseType, typename Dummy = void> struct Chainer {
explicit Chainer(const std::shared_ptr<Private::Core> &core)
: chainCore(core) {}
void operator()(const PromiseType& val) {
void operator()(const PromiseType &val) {
chainCore->construct<PromiseType>(val);
for (const auto& req: chainCore->requests) {
for (const auto &req : chainCore->requests) {
req->resolve(chainCore);
}
}
......@@ -633,17 +550,15 @@ namespace Async {
std::shared_ptr<Core> chainCore;
};
template<typename Dummy>
struct Chainer<void, Dummy> {
explicit Chainer(const std::shared_ptr<Private::Core>& core)
: chainCore(core)
{ }
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) {
for (const auto &req : chainCore->requests) {
req->resolve(chainCore);
}
}
......@@ -651,23 +566,20 @@ namespace Async {
std::shared_ptr<Core> chainCore;
};
template<
typename Promise,
template <typename Promise,
typename Type = typename detail::RemovePromise<Promise>::Type>
Chainer<Type>
makeChainer(const Promise&) {
Chainer<Type> makeChainer(const Promise &) {
return Chainer<Type>(this->chain_);
}
template<typename P>
void finishResolve(P& promise) {
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) {
for (const auto &req : core->requests) {
req->reject(core);
}
});
......@@ -675,93 +587,80 @@ namespace Async {
Resolve resolve_;
Reject reject_;
};
};
} // namespace impl
} // namespace impl
template<typename T, typename Resolve, typename Reject, typename Sig>
struct Continuation : public impl::Continuation<T, Resolve, Reject, decltype(&Sig::operator())>
{
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;
typedef impl::Continuation<T, Resolve, Reject, decltype(&Sig::operator())>
Base;
Continuation(
const std::shared_ptr<Core>& core,
Resolve resolve,
Continuation(const std::shared_ptr<Core> &core, Resolve resolve,
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>
struct Continuation<T, Resolve, Reject, Res (*)(Args...)> : public impl::Continuation<T, Resolve, Reject, Res (Args...)>
{
typedef impl::Continuation<T, Resolve, Reject, Res (Args...)> Base;
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,
Continuation(const std::shared_ptr<Core> &core, Resolve resolve,
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>
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;
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,
Continuation(const std::shared_ptr<Core> &core, Resolve resolve,
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>
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;
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,
Continuation(const std::shared_ptr<Core> &core, Resolve resolve,
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>
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;
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,
Continuation(const std::shared_ptr<Core> &core, Resolve resolve,
Reject reject)
: Base(core, std::move(resolve), std::move(reject))
{ }
};
}
: Base(core, std::move(resolve), std::move(reject)) {}
};
} // namespace Private
class Resolver {
public:
class Resolver {
public:
explicit Resolver(const std::shared_ptr<Private::Core> &core) : core_(core) {}
explicit Resolver(const std::shared_ptr<Private::Core> &core)
: core_(core)
{ }
Resolver(const Resolver &other) = delete;
Resolver &operator=(const Resolver &other) = delete;
Resolver(const Resolver& other) = delete;
Resolver& operator=(const Resolver& other) = delete;
Resolver(Resolver &&other) = default;
Resolver &operator=(Resolver &&other) = default;
Resolver(Resolver&& other) = default;
Resolver& operator=(Resolver&& other) = default;
template<typename Arg>
bool operator()(Arg&& arg) const {
if (!core_) return false;
template <typename Arg> bool operator()(Arg &&arg) const {
if (!core_)
return false;
typedef typename std::remove_reference<Arg>::type Type;
......@@ -779,7 +678,7 @@ namespace Async {
std::unique_lock<std::mutex> guard(core_->mtx);
core_->construct<Type>(std::forward<Arg>(arg));
for (const auto& req: core_->requests) {
for (const auto &req : core_->requests) {
req->resolve(core_);
}
......@@ -787,7 +686,8 @@ namespace Async {
}
bool operator()() const {
if (!core_) return false;
if (!core_)
return false;
if (core_->state != State::Pending)
throw Error("Attempt to resolve a fulfilled promise");
......@@ -797,41 +697,35 @@ namespace Async {
std::unique_lock<std::mutex> guard(core_->mtx);
core_->state = State::Fulfilled;
for (const auto& req: core_->requests) {
for (const auto &req : core_->requests) {
req->resolve(core_);
}
return true;
}
void clear() {
core_ = nullptr;
}
void clear() { core_ = nullptr; }
Resolver clone() {
return Resolver(core_);
}
Resolver clone() { return Resolver(core_); }
private:
private:
std::shared_ptr<Private::Core> core_;
};
};
class Rejection {
public:
class Rejection {
public:
explicit Rejection(const std::shared_ptr<Private::Core> &core)
: core_(core) {}
explicit Rejection(const std::shared_ptr<Private::Core>& core)
: core_(core)
{ }
Rejection(const Rejection &other) = delete;
Rejection &operator=(const Rejection &other) = delete;
Rejection(const Rejection& other) = delete;
Rejection& operator=(const Rejection& other) = delete;
Rejection(Rejection &&other) = default;
Rejection &operator=(Rejection &&other) = default;
Rejection(Rejection&& other) = default;
Rejection& operator=(Rejection&& other) = default;
template<typename Exc>
bool operator()(Exc exc) const {
if (!core_) return false;
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");
......@@ -839,62 +733,47 @@ namespace Async {
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) {
for (const auto &req : core_->requests) {
req->reject(core_);
}
return true;
}
void clear() {
core_ = nullptr;
}
void clear() { core_ = nullptr; }
Rejection clone() {
return Rejection(core_);
}
Rejection clone() { return Rejection(core_); }
private:
private:
std::shared_ptr<Private::Core> core_;
};
};
template<typename T>
class Deferred {
public:
Deferred()
: resolver(nullptr)
, rejection(nullptr)
{ }
template <typename T> class Deferred {
public:
Deferred() : resolver(nullptr), rejection(nullptr) {}
Deferred(const Deferred& other) = delete;
Deferred& operator=(const Deferred& other) = delete;
Deferred(const Deferred &other) = delete;
Deferred &operator=(const Deferred &other) = delete;
Deferred(Deferred&& other) = default;
Deferred& operator=(Deferred&& other) = default;
Deferred(Deferred &&other) = default;
Deferred &operator=(Deferred &&other) = default;
Deferred(Resolver _resolver, Rejection _reject)
: resolver(std::move(_resolver))
, rejection(std::move(_reject))
{ }
: resolver(std::move(_resolver)), rejection(std::move(_reject)) {}
template<typename U>
bool resolve(U&& arg) {
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,
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... Args> void emplaceResolve(Args &&...) {}
template<typename Exc>
bool reject(Exc exc) {
template <typename Exc> bool reject(Exc exc) {
return rejection(std::move(exc));
}
......@@ -903,104 +782,81 @@ namespace Async {
rejection.clear();
}
private:
private:
Resolver resolver;
Rejection rejection;
};
};
template<>
class Deferred<void> {
public:
template <> class Deferred<void> {
public:
Deferred() : resolver(nullptr), rejection(nullptr) {}
Deferred()
: resolver(nullptr)
, rejection(nullptr)
{ }
Deferred(const Deferred &other) = delete;
Deferred &operator=(const Deferred &other) = delete;
Deferred(const Deferred& other) = delete;
Deferred& operator=(const Deferred& other) = delete;
Deferred(Deferred&& other) = default;
Deferred& operator=(Deferred&& other) = default;
Deferred(Deferred &&other) = default;
Deferred &operator=(Deferred &&other) = default;
Deferred(Resolver _resolver, Rejection _reject)
: resolver(std::move(_resolver))
, rejection(std::move(_reject))
{ }
: resolver(std::move(_resolver)), rejection(std::move(_reject)) {}
void resolve() {
resolver();
}
void resolve() { resolver(); }
template<typename Exc>
void reject(Exc _exc) {
rejection(std::move(_exc));
}
template <typename Exc> void reject(Exc _exc) { rejection(std::move(_exc)); }
private:
private:
Resolver resolver;
Rejection rejection;
};
};
static constexpr Private::IgnoreException IgnoreException{};
static constexpr Private::NoExcept NoExcept{};
static constexpr Private::Throw Throw{};
static constexpr Private::IgnoreException IgnoreException{};
static constexpr Private::NoExcept NoExcept{};
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
* However, gcc 4.7 does not correctly support std::result_of for SFINAE purposes, so we
* use a decltype SFINAE-expression instead.
/*
* 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)
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)
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;
template <typename T> class Promise : public PromiseBase {
public:
template <typename U> friend class Promise;
typedef Private::CoreT<T> Core;
template<typename Func>
template <typename Func>
explicit Promise(Func func)
: core_(std::make_shared<Core>())
, resolver_(core_)
, rejection_(core_)
{
: 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(const Promise<T> &other) = delete;
Promise &operator=(const Promise<T> &other) = delete;
Promise(Promise<T>&& other) = default;
Promise& operator=(Promise<T>&& other) = default;
Promise(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,
"Can not resolve a void promise with parameters");
static_assert(std::is_same<T, U>::value || std::is_convertible<U, T>::value,
......@@ -1011,9 +867,7 @@ namespace Async {
return Promise<T>(std::move(core));
}
static
Promise<void>
resolved() {
static Promise<void> resolved() {
static_assert(std::is_void<T>::value,
"Resolving a non-void promise requires parameters");
......@@ -1022,9 +876,7 @@ namespace Async {
return Promise<T>(std::move(core));
}
template<typename Exc>
static Promise<T>
rejected(Exc exc) {
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;
......@@ -1035,30 +887,25 @@ namespace Async {
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
>
{
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;
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);
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()) {
} else if (isRejected()) {
req->reject(core_);
}
......@@ -1067,55 +914,52 @@ namespace Async {
return promise;
}
private:
private:
Promise()
: core_(std::make_shared<Core>())
, resolver_(core_)
, rejection_(core_)
{
}
: core_(std::make_shared<Core>()), resolver_(core_), rejection_(core_) {}
explicit Promise(std::shared_ptr<Core>&& core)
: core_(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) {
}
template <typename T> class Barrier {
public:
explicit Barrier(Promise<T> &promise) : promise_(promise) {}
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);
cv.notify_one();
}, [&](std::exception_ptr) mutable {
},
[&](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(); });
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;
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 {
promise_.then(
[&](const T &) mutable {
std::unique_lock<std::mutex> guard(mtx);
cv.notify_one();
}, [&](std::exception_ptr) mutable {
},
[&](std::exception_ptr) mutable {
std::unique_lock<std::mutex> guard(mtx);
cv.notify_one();
});
......@@ -1124,64 +968,54 @@ namespace Async {
return cv.wait_for(guard, period);
}
private:
Promise<T>& promise_;
private:
Promise<T> &promise_;
mutable std::mutex mtx;
std::condition_variable cv;
};
};
namespace Impl {
struct Any;
}
namespace Impl {
struct Any;
}
class Any {
public:
class Any {
public:
friend struct Impl::Any;
Any(const Any& other) = default;
Any& operator=(const Any& other) = default;
Any(const Any &other) = default;
Any &operator=(const Any &other) = default;
Any(Any&& other) = default;
Any& operator=(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> bool is() const { return core_->id == TypeId::of<T>(); }
template<typename T>
T cast() const {
if (!is<T>()) throw BadAnyCast();
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)
{ }
private:
explicit Any(const std::shared_ptr<Private::Core> &core) : 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
* 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 ?
/* 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 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))
{ }
: total(_total), resolved(0), rejected(false), mtx(),
resolve(std::move(_resolver)), reject(std::move(_rejection)) {}
const size_t total;
size_t resolved;
......@@ -1192,11 +1026,12 @@ namespace Async {
Rejection reject;
};
template<size_t Index, typename T, typename Data>
static void resolveT(const T& val, Data& data) {
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;
if (data->rejected)
return;
// @Check thread-safety of std::get ?
std::get<Index>(data->results) = val;
......@@ -1207,11 +1042,11 @@ namespace Async {
}
}
template<typename Data>
static void resolveVoid(Data& data) {
template <typename Data> static void resolveVoid(Data &data) {
std::lock_guard<std::mutex> guard(data->mtx);
if (data->rejected) return;
if (data->rejected)
return;
data->resolved++;
......@@ -1220,24 +1055,21 @@ namespace Async {
}
}
template<typename Data>
static void reject(std::exception_ptr exc, Data& data) {
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 Any {
struct Data {
Data(size_t, Resolver resolver, Rejection rejection)
: done(false)
, mtx()
, resolve(std::move(resolver))
, reject(std::move(rejection))
{ }
: done(false), mtx(), resolve(std::move(resolver)),
reject(std::move(rejection)) {}
bool done;
std::mutex mtx;
......@@ -1246,14 +1078,16 @@ namespace Async {
Rejection reject;
};
template<size_t Index, typename T, typename Data>
static void resolveT(const T& val, Data& data) {
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;
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
// 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));
......@@ -1261,11 +1095,11 @@ namespace Async {
data->done = true;
}
template<typename Data>
static void resolveVoid(Data& data) {
template <typename Data> static void resolveVoid(Data &data) {
std::lock_guard<std::mutex> guard(data->mtx);
if (data->done) return;
if (data->done)
return;
auto core = std::make_shared<Private::CoreT<void>>();
data->resolve(Async::Any(core));
......@@ -1273,139 +1107,114 @@ namespace Async {
data->done = true;
}
template<typename Data>
static void reject(std::exception_ptr exc, Data& data) {
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 {
template <typename ContinuationPolicy> struct When {
When(Resolver resolver, Rejection rejection)
: resolve(std::move(resolver))
, reject(std::move(rejection))
{ }
: resolve(std::move(resolver)), reject(std::move(rejection)) {}
template<typename... Args>
void operator()(Args&&... args) {
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))
{ }
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 {
void operator()(const T &val) const {
ContinuationPolicy::template resolveT<Index>(val, data);
}
Data data;
};
template<size_t Index, typename Data>
template <size_t Index, typename Data>
struct WhenContinuation<void, Index, Data> {
explicit WhenContinuation(Data _data)
: data(std::move(_data))
{ }
explicit WhenContinuation(Data _data) : data(std::move(_data)) {}
void operator()() const {
ContinuationPolicy::resolveVoid(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) {
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) {
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) {
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;
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.
/* 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))
{ }
: 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));
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) {
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) {
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
{
template <typename T, typename Results> struct WhenAllRange {
WhenAllRange(Resolver _resolve, Rejection _reject)
: resolve(std::move(_resolve))
, reject(std::move(_reject))
{ }
: resolve(std::move(_resolve)), reject(std::move(_reject)) {}
template<typename Iterator>
void operator()(Iterator first, Iterator last)
{
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)
);
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) {
......@@ -1415,7 +1224,8 @@ namespace Async {
it->then(std::move(cont), [=](std::exception_ptr ptr) {
std::lock_guard<std::mutex> guard(data->mtx);
if (data->rejected) return;
if (data->rejected)
return;
data->rejected = true;
data->reject(std::move(ptr));
......@@ -1425,17 +1235,11 @@ namespace Async {
}
}
private:
struct Data
{
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))
{ }
: total(_total), resolved(0), rejected(false), mtx(),
resolve(std::move(_resolver)), reject(std::move(_rejection)) {}
const size_t total;
size_t resolved;
......@@ -1450,10 +1254,10 @@ namespace Async {
* here, so you know what, compiler ? Take that Dummy type and leave
* 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)
: Data(total, std::move(resolver), std::move(rejection))
{
: Data(total, std::move(resolver), std::move(rejection)) {
results.resize(total);
}
......@@ -1463,33 +1267,26 @@ namespace Async {
/* 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 {
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))
{
}
: Data(total, std::move(resolver), std::move(rejection)) {}
};
template<typename ValueType, typename Dummy = void>
struct WhenContinuation
{
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)
{ }
WhenContinuation(const D &_data, size_t _index)
: data(_data), index(_index) {}
void operator()(const ValueType& val) const
{
void operator()(const ValueType &val) const {
std::lock_guard<std::mutex> guard(data->mtx);
if (data->rejected) return;
if (data->rejected)
return;
data->results[index] = val;
data->resolved++;
if (data->resolved == data->total)
{
if (data->resolved == data->total) {
data->resolve(data->results);
}
}
......@@ -1498,24 +1295,19 @@ namespace Async {
size_t index;
};
template<typename Dummy>
struct WhenContinuation<void, Dummy>
{
template <typename Dummy> struct WhenContinuation<void, Dummy> {
using D = std::shared_ptr<DataT<void>>;
WhenContinuation(const D& _data, size_t)
: data(_data)
{ }
WhenContinuation(const D &_data, size_t) : data(_data) {}
void operator()() const
{
void operator()() const {
std::lock_guard<std::mutex> guard(data->mtx);
if (data->rejected) return;
if (data->rejected)
return;
data->resolved++;
if (data->resolved == data->total)
{
if (data->resolved == data->total) {
data->resolve();
}
}
......@@ -1525,27 +1317,21 @@ namespace Async {
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) {
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;
Resolver *resolve;
Rejection *reject;
Promise<Results> promise([&](Resolver& resolver, Rejection& rejection) {
Promise<Results> promise([&](Resolver &resolver, Rejection &rejection) {
resolve = &resolver;
reject = &rejection;
});
......@@ -1556,15 +1342,14 @@ namespace Async {
impl(std::forward<Args>(args)...);
return promise;
}
}
template<typename... Args>
Promise<Any> whenAny(Args&& ...args) {
template <typename... Args> Promise<Any> whenAny(Args &&... args) {
// Same trick as above;
Resolver* resolve;
Rejection* reject;
Resolver *resolve;
Rejection *reject;
Promise<Any> promise([&](Resolver& resolver, Rejection& rejection) {
Promise<Any> promise([&](Resolver &resolver, Rejection &rejection) {
resolve = &resolver;
reject = &rejection;
});
......@@ -1572,32 +1357,24 @@ namespace Async {
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) {
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));
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
......@@ -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 {
......
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