From 36f0bb49e5c3efbf9363b245e42ebdd74a0ab9ee Mon Sep 17 00:00:00 2001 From: Determinant Date: Fri, 2 Feb 2018 23:51:49 -0500 Subject: more friendly interface --- promise.hpp | 204 +++++++++++++++++++++++++++++------------------------------- test.cpp | 7 ++- 2 files changed, 105 insertions(+), 106 deletions(-) diff --git a/promise.hpp b/promise.hpp index 3d38438..97f7464 100644 --- a/promise.hpp +++ b/promise.hpp @@ -41,8 +41,6 @@ * Javascript Promise/A+. */ namespace promise { - using std::function; - #if defined(__cpp_lib_any) using pm_any_t = std::any; template @@ -55,63 +53,60 @@ namespace promise { constexpr auto any_cast = static_cast(boost::any_cast); using bad_any_cast = boost::bad_any_cast; #endif - struct None {}; - using values_t = std::vector; const auto none = None(); - const auto do_nothing = [](){}; + using callback_t = std::function; + using values_t = std::vector; /* match lambdas */ template struct function_traits: public function_traits {}; - + + template + struct function_traits { + using ret_type = ReturnType; + using arg_type = None; + using empty_arg = void; + }; + /* match plain functions */ template struct function_traits { using ret_type = ReturnType; using arg_type = ArgType; + using non_empty_arg = void; }; - + /* match function pointers */ - template - struct function_traits: - public function_traits {}; + template + struct function_traits: + public function_traits {}; /* match const member functions */ - template - struct function_traits: - public function_traits {}; + template + struct function_traits: + public function_traits {}; /* match member functions */ - template - struct function_traits: - public function_traits {}; + template + struct function_traits: + public function_traits {}; class Promise; - class promise_t { - std::shared_ptr ptr; + class promise_t: std::shared_ptr { public: - + friend Promise; + template friend promise_t all(PList promise_list); template - promise_t(Func callback) { - ptr = std::make_shared(); + promise_t(Func callback): + std::shared_ptr(std::make_shared()) { callback(*this); } template inline void resolve(T result) const; template inline void reject(T reason) const; - template - inline promise_t then_any(FuncFulfilled fulfilled_callback, - FuncRejected rejected_callback) const; - - template - inline promise_t then_any(FuncFulfilled fulfilled_callback) const; - - template - inline promise_t fail_any(FuncRejected rejected_callback) const; - template inline promise_t then(FuncFulfilled on_fulfilled) const; @@ -127,8 +122,8 @@ namespace promise { #define PROMISE_ERR_MISMATCH_TYPE do {throw std::runtime_error("mismatching promise value types");} while (0) class Promise { - std::vector> fulfilled_callbacks; - std::vector> rejected_callbacks; + std::vector fulfilled_callbacks; + std::vector rejected_callbacks; enum class State { Pending, Fulfilled, @@ -137,11 +132,11 @@ namespace promise { pm_any_t result; pm_any_t reason; - void add_on_fulfilled(function cb) { + void add_on_fulfilled(callback_t cb) { fulfilled_callbacks.push_back(cb); } - void add_on_rejected(function cb) { + void add_on_rejected(callback_t cb) { rejected_callbacks.push_back(cb); } @@ -149,15 +144,15 @@ namespace promise { typename std::enable_if< std::is_same::ret_type, promise_t>::value>::type - gen_on_fulfilled(Func on_fulfilled, const promise_t &npm, function &ret) { + gen_on_fulfilled(Func on_fulfilled, const promise_t &npm, callback_t &ret) { ret = [this, on_fulfilled, npm]() mutable { - on_fulfilled(result).then_any( + on_fulfilled(result)->then( [npm] (pm_any_t result_) { - npm.resolve(result_); + npm->resolve(result_); return pm_any_t(none); }, [npm] (pm_any_t reason_) { - npm.reject(reason_); + npm->reject(reason_); return pm_any_t(none); }); }; @@ -167,9 +162,9 @@ namespace promise { typename std::enable_if< std::is_same::ret_type, pm_any_t>::value>::type - gen_on_fulfilled(Func on_fulfilled, const promise_t &npm, function &ret) { + gen_on_fulfilled(Func on_fulfilled, const promise_t &npm, callback_t &ret) { ret = [this, on_fulfilled, npm]() mutable { - npm.resolve(on_fulfilled(result)); + npm->resolve(on_fulfilled(result)); }; } @@ -177,15 +172,15 @@ namespace promise { typename std::enable_if< std::is_same::ret_type, promise_t>::value>::type - gen_on_rejected(Func on_rejected, const promise_t &npm, function &ret) { + gen_on_rejected(Func on_rejected, const promise_t &npm, callback_t &ret) { ret = [this, on_rejected, npm]() mutable { - on_rejected(reason).then_any( + on_rejected(reason)->then( [npm] (pm_any_t result_) { - npm.resolve(result_); + npm->resolve(result_); return pm_any_t(none); }, [npm] (pm_any_t reason_) { - npm.reject(reason_); + npm->reject(reason_); return pm_any_t(none); }); }; @@ -195,9 +190,9 @@ namespace promise { typename std::enable_if< std::is_same::ret_type, pm_any_t>::value>::type - gen_on_rejected(Func on_rejected, const promise_t &npm, function &ret) { + gen_on_rejected(Func on_rejected, const promise_t &npm, callback_t &ret) { ret = [this, on_rejected, npm]() mutable { - npm.reject(on_rejected(reason)); + npm->reject(on_rejected(reason)); }; } @@ -213,7 +208,7 @@ namespace promise { { case State::Pending: return promise_t([this, on_fulfilled, on_rejected](promise_t npm) { - function ret; + callback_t ret; gen_on_fulfilled(on_fulfilled, npm, ret); add_on_fulfilled(ret); gen_on_rejected(on_rejected, npm, ret); @@ -221,13 +216,13 @@ namespace promise { }); case State::Fulfilled: return promise_t([this, on_fulfilled](promise_t npm) { - function ret; + callback_t ret; gen_on_fulfilled(on_fulfilled, npm, ret); ret(); }); case State::Rejected: return promise_t([this, on_rejected](promise_t npm) { - function ret; + callback_t ret; gen_on_rejected(on_rejected, npm, ret); ret(); }); @@ -241,19 +236,19 @@ namespace promise { { case State::Pending: return promise_t([this, on_fulfilled](promise_t npm) { - function ret; + callback_t ret; gen_on_fulfilled(on_fulfilled, npm, ret); add_on_fulfilled(ret); - add_on_rejected([this, npm]() {npm.reject(reason);}); + add_on_rejected([this, npm]() {npm->reject(reason);}); }); case State::Fulfilled: return promise_t([this, on_fulfilled](promise_t npm) { - function ret; + callback_t ret; gen_on_fulfilled(on_fulfilled, npm, ret); ret(); }); case State::Rejected: - return promise_t([this](promise_t npm) {npm.reject(reason);}); + return promise_t([this](promise_t npm) {npm->reject(reason);}); default: PROMISE_ERR_INVALID_STATE; } } @@ -264,16 +259,16 @@ namespace promise { { case State::Pending: return promise_t([this, on_rejected](promise_t npm) { - function ret; + callback_t ret; gen_on_rejected(on_rejected, npm, ret); add_on_rejected(ret); - add_on_fulfilled([this, npm]() {npm.resolve(result);}); + add_on_fulfilled([this, npm]() {npm->resolve(result);}); }); case State::Fulfilled: - return promise_t([this](promise_t npm) {npm.resolve(result);}); + return promise_t([this](promise_t npm) {npm->resolve(result);}); case State::Rejected: return promise_t([this, on_rejected](promise_t npm) { - function ret; + callback_t ret; gen_on_rejected(on_rejected, npm, ret); ret(); }); @@ -318,15 +313,15 @@ namespace promise { results->resize(*size); size_t idx = 0; for (const auto &pm: promise_list) { - pm.then_any( + pm->then( [results, size, idx, npm](pm_any_t result) { (*results)[idx] = result; if (!--(*size)) - npm.resolve(*results); + npm->resolve(*results); return pm_any_t(none); }, [npm, size](pm_any_t reason) { - npm.reject(reason); + npm->reject(reason); return pm_any_t(none); }); idx++; @@ -335,51 +330,50 @@ namespace promise { } template - inline void promise_t::resolve(T result) const { ptr->resolve(result); } - - template - inline void promise_t::reject(T reason) const { ptr->reject(reason); } - - template - inline promise_t promise_t::then_any(FuncFulfilled fulfilled_callback, - FuncRejected rejected_callback) const { - return ptr->then(fulfilled_callback, rejected_callback); - } - - template - inline promise_t promise_t::then_any(FuncFulfilled fulfilled_callback) const { - return ptr->then(fulfilled_callback); - } - - template - inline promise_t promise_t::fail_any(FuncRejected rejected_callback) const { - return ptr->fail(rejected_callback); - } + inline void promise_t::resolve(T result) const { (*this)->resolve(result); } template - struct callback_type_conversion { - using type = pm_any_t; - }; - - template<> - struct callback_type_conversion { - using type = promise_t; - }; + inline void promise_t::reject(T reason) const { (*this)->reject(reason); } template struct callback_types { using arg_type = typename function_traits::arg_type; - using ret_type = typename callback_type_conversion::ret_type>::type; + using ret_type = typename std::conditional< + std::is_same::ret_type, promise_t>::value, + promise_t, pm_any_t>::type; }; + template::ret_type, + void>::value>::type * = nullptr> + constexpr auto convert_void_func_(Func f) { + return [f](typename function_traits::arg_type v) { + f(v); + return none; + }; + } + + template::ret_type, + void>::value>::type * = nullptr> + constexpr auto convert_void_func_(Func f) { return f; } + + template::empty_arg * = nullptr> + constexpr auto convert_void_func(Func f) { return convert_void_func_([f](None) {f();}); } + + template::non_empty_arg * = nullptr> + constexpr auto convert_void_func(Func f) { return convert_void_func_(f); } + template inline promise_t promise_t::then(FuncFulfilled on_fulfilled) const { - using arg_type = typename callback_types::arg_type; - using ret_type = typename callback_types::ret_type; - return ptr->then( + using fulfill_t = callback_types; + return (*this)->then( [on_fulfilled](pm_any_t _result) mutable { try { - return ret_type(on_fulfilled(any_cast(_result))); + return typename fulfill_t::ret_type(convert_void_func(on_fulfilled)( + any_cast(_result))); } catch (bad_any_cast e) { PROMISE_ERR_MISMATCH_TYPE; } }); } @@ -387,31 +381,31 @@ namespace promise { template inline promise_t promise_t::then(FuncFulfilled on_fulfilled, FuncRejected on_rejected) const { - using fulfill_arg_type = typename callback_types::arg_type; - using fulfill_ret_type = typename callback_types::ret_type; - using reject_arg_type = typename callback_types::arg_type; - using reject_ret_type = typename callback_types::ret_type; - return ptr->then( + using fulfill_t = callback_types; + using reject_t = callback_types; + return (*this)->then( [on_fulfilled](pm_any_t _result) mutable { try { - return fulfill_ret_type(on_fulfilled(any_cast(_result))); + return typename fulfill_t::ret_type(convert_void_func(on_fulfilled)( + any_cast(_result))); } catch (bad_any_cast e) { PROMISE_ERR_MISMATCH_TYPE; } }, [on_rejected](pm_any_t _reason) mutable { try { - return reject_ret_type(on_rejected(any_cast(_reason))); + return typename reject_t::ret_type(convert_void_func(on_rejected)( + any_cast(_reason))); } catch (bad_any_cast e) { PROMISE_ERR_MISMATCH_TYPE; } }); } template inline promise_t promise_t::fail(FuncRejected on_rejected) const { - using arg_type = typename callback_types::arg_type; - using ret_type = typename callback_types::ret_type; - return ptr->fail( + using reject_t = callback_types; + return (*this)->fail( [on_rejected](pm_any_t _reason) mutable { try { - return ret_type(on_rejected(any_cast(_reason))); + return typename reject_t::ret_type(convert_void_func(on_rejected)( + any_cast(_reason))); } catch (bad_any_cast e) { PROMISE_ERR_MISMATCH_TYPE; } }); } diff --git a/test.cpp b/test.cpp index d99806f..62a07de 100644 --- a/test.cpp +++ b/test.cpp @@ -57,7 +57,12 @@ int main() { }).then([](int x) { printf("%d\n", x); return 12; - }).then(f).then(a1).fail(a2).then(b1).fail(b2).then(g).then(a3, b3); + }).then(f).then(a1).fail(a2).then(b1).fail(b2).then(g).then(a3, b3) + .then([](int x) { + puts("void return will automatically yield promise::none"); + }).then([]() { + puts("void parameter will automatically be promise::None"); + }); auto p1 = promise_t([&t4](promise_t pm) { puts("p1"); -- cgit v1.2.3