aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDeterminant <ted.sybil@gmail.com>2018-02-03 15:45:55 -0500
committerDeterminant <ted.sybil@gmail.com>2018-02-03 15:45:55 -0500
commit86b1bab87e0a4049f6fc9d2fedec323556f5ef27 (patch)
tree27d68bb22c9e2a956b515bef326e1da65934eb67
parent36f0bb49e5c3efbf9363b245e42ebdd74a0ab9ee (diff)
eliminate the need for promise::None
-rw-r--r--Makefile4
-rw-r--r--promise.hpp311
-rw-r--r--test.cpp8
3 files changed, 190 insertions, 133 deletions
diff --git a/Makefile b/Makefile
index 46ebf2e..3ac8bff 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
.PHONY: all
all: test14 test17
test14: test.cpp promise.hpp
- g++ -o $@ test.cpp -std=c++17
+ g++ -o $@ test.cpp -std=c++14 -Wall -Wextra -Wpedantic -O2
test17: test.cpp promise.hpp
- g++ -o $@ test.cpp -std=c++14
+ g++ -o $@ test.cpp -std=c++17 -Wall -Wextra -Wpedantic -O2
diff --git a/promise.hpp b/promise.hpp
index 97f7464..8fdf14e 100644
--- a/promise.hpp
+++ b/promise.hpp
@@ -47,14 +47,13 @@ namespace promise {
constexpr auto any_cast = static_cast<T(*)(const std::any&)>(std::any_cast<T>);
using bad_any_cast = std::bad_any_cast;
#else
-#warning "using any type from boost"
+#warning "using boost::any"
+#pragma message "using boost::any"
using pm_any_t = boost::any;
template<typename T>
constexpr auto any_cast = static_cast<T(*)(const boost::any&)>(boost::any_cast<T>);
using bad_any_cast = boost::bad_any_cast;
#endif
- struct None {};
- const auto none = None();
using callback_t = std::function<void()>;
using values_t = std::vector<pm_any_t>;
@@ -66,7 +65,7 @@ namespace promise {
template<typename ReturnType>
struct function_traits<ReturnType()> {
using ret_type = ReturnType;
- using arg_type = None;
+ using arg_type = void;
using empty_arg = void;
};
@@ -93,6 +92,16 @@ namespace promise {
struct function_traits<ReturnType(ClassType::*)(ArgType...)>:
public function_traits<ReturnType(ArgType...)> {};
+ template<typename Func, typename ReturnType>
+ using enable_if_return = typename std::enable_if<
+ std::is_same<typename function_traits<Func>::ret_type,
+ ReturnType>::value>;
+
+ template<typename Func, typename ReturnType>
+ using disable_if_return = typename std::enable_if<
+ !std::is_same<typename function_traits<Func>::ret_type,
+ ReturnType>::value>;
+
class Promise;
class promise_t: std::shared_ptr<Promise> {
public:
@@ -106,6 +115,8 @@ namespace promise {
template<typename T> inline void resolve(T result) const;
template<typename T> inline void reject(T reason) const;
+ inline void resolve() const;
+ inline void reject() const;
template<typename FuncFulfilled>
inline promise_t then(FuncFulfilled on_fulfilled) const;
@@ -140,62 +151,133 @@ namespace promise {
rejected_callbacks.push_back(cb);
}
- template<typename Func>
- typename std::enable_if<
- std::is_same<typename function_traits<Func>::ret_type,
- promise_t>::value>::type
- gen_on_fulfilled(Func on_fulfilled, const promise_t &npm, callback_t &ret) {
- ret = [this, on_fulfilled, npm]() mutable {
- on_fulfilled(result)->then(
+ template<typename Func, typename function_traits<Func>::non_empty_arg * = nullptr>
+ static constexpr auto cps_transform(Func f, const pm_any_t &result, const promise_t &npm) {
+ return [&result, f, npm]() mutable {
+ f(result)->then(
[npm] (pm_any_t result_) {
npm->resolve(result_);
- return pm_any_t(none);
},
[npm] (pm_any_t reason_) {
npm->reject(reason_);
- return pm_any_t(none);
});
};
}
- template<typename Func>
- typename std::enable_if<
- std::is_same<typename function_traits<Func>::ret_type,
- pm_any_t>::value>::type
- gen_on_fulfilled(Func on_fulfilled, const promise_t &npm, callback_t &ret) {
- ret = [this, on_fulfilled, npm]() mutable {
- npm->resolve(on_fulfilled(result));
- };
- }
-
- template<typename Func>
- typename std::enable_if<
- std::is_same<typename function_traits<Func>::ret_type,
- promise_t>::value>::type
- gen_on_rejected(Func on_rejected, const promise_t &npm, callback_t &ret) {
- ret = [this, on_rejected, npm]() mutable {
- on_rejected(reason)->then(
+ template<typename Func, typename function_traits<Func>::empty_arg * = nullptr>
+ static constexpr auto cps_transform(Func f, const pm_any_t &, const promise_t &npm) {
+ return [f, npm]() mutable {
+ f()->then(
[npm] (pm_any_t result_) {
npm->resolve(result_);
- return pm_any_t(none);
},
[npm] (pm_any_t reason_) {
npm->reject(reason_);
- return pm_any_t(none);
});
};
}
- template<typename Func>
- typename std::enable_if<
- std::is_same<typename function_traits<Func>::ret_type,
- pm_any_t>::value>::type
- gen_on_rejected(Func on_rejected, const promise_t &npm, callback_t &ret) {
- ret = [this, on_rejected, npm]() mutable {
+ template<typename Func,
+ typename enable_if_return<Func, promise_t>::type * = nullptr>
+ constexpr auto gen_on_fulfilled(Func on_fulfilled, const promise_t &npm) {
+ return cps_transform(on_fulfilled, this->result, npm);
+ }
+
+ template<typename Func,
+ typename enable_if_return<Func, promise_t>::type * = nullptr>
+ constexpr auto gen_on_rejected(Func on_rejected, const promise_t &npm) {
+ return cps_transform(on_rejected, this->reason, npm);
+ }
+
+
+ template<typename Func,
+ typename enable_if_return<Func, void>::type * = nullptr,
+ typename function_traits<Func>::non_empty_arg * = nullptr>
+ constexpr auto gen_on_fulfilled(Func on_fulfilled, const promise_t &npm) {
+ return [this, on_fulfilled, npm]() mutable {
+ on_fulfilled(result);
+ npm->resolve();
+ };
+ }
+
+ template<typename Func,
+ typename enable_if_return<Func, void>::type * = nullptr,
+ typename function_traits<Func>::empty_arg * = nullptr>
+ constexpr auto gen_on_fulfilled(Func on_fulfilled, const promise_t &npm) {
+ return [on_fulfilled, npm]() mutable {
+ on_fulfilled();
+ npm->resolve();
+ };
+ }
+
+ template<typename Func,
+ typename enable_if_return<Func, void>::type * = nullptr,
+ typename function_traits<Func>::non_empty_arg * = nullptr>
+ constexpr auto gen_on_rejected(Func on_rejected, const promise_t &npm) {
+ return [this, on_rejected, npm]() mutable {
+ on_rejected(reason);
+ npm->reject();
+ };
+ }
+
+ template<typename Func,
+ typename enable_if_return<Func, void>::type * = nullptr,
+ typename function_traits<Func>::empty_arg * = nullptr>
+ constexpr auto gen_on_rejected(Func on_rejected, const promise_t &npm) {
+ return [on_rejected, npm]() mutable {
+ on_rejected();
+ npm->reject();
+ };
+ }
+
+ template<typename Func,
+ typename enable_if_return<Func, pm_any_t>::type * = nullptr,
+ typename function_traits<Func>::non_empty_arg * = nullptr>
+ constexpr auto gen_on_fulfilled(Func on_fulfilled, const promise_t &npm) {
+ return [this, on_fulfilled, npm]() mutable {
+ npm->resolve(on_fulfilled(result));
+ };
+ }
+
+ template<typename Func,
+ typename enable_if_return<Func, pm_any_t>::type * = nullptr,
+ typename function_traits<Func>::empty_arg * = nullptr>
+ constexpr auto gen_on_fulfilled(Func on_fulfilled, const promise_t &npm) {
+ return [on_fulfilled, npm]() mutable {
+ npm->resolve(on_fulfilled());
+ };
+ }
+
+ template<typename Func,
+ typename enable_if_return<Func, pm_any_t>::type * = nullptr,
+ typename function_traits<Func>::non_empty_arg * = nullptr>
+ constexpr auto gen_on_rejected(Func on_rejected, const promise_t &npm) {
+ return [this, on_rejected, npm]() mutable {
npm->reject(on_rejected(reason));
};
}
+ template<typename Func,
+ typename enable_if_return<Func, pm_any_t>::type * = nullptr,
+ typename function_traits<Func>::empty_arg * = nullptr>
+ constexpr auto gen_on_rejected(Func on_rejected, const promise_t &npm) {
+ return [on_rejected, npm]() mutable {
+ npm->reject(on_rejected());
+ };
+ }
+
+ void trigger_fulfill() {
+ state = State::Fulfilled;
+ for (const auto &cb: fulfilled_callbacks) cb();
+ fulfilled_callbacks.clear();
+ }
+
+ void trigger_reject() {
+ state = State::Rejected;
+ for (const auto &cb: rejected_callbacks) cb();
+ rejected_callbacks.clear();
+ }
+
public:
Promise(): state(State::Pending) {}
@@ -208,23 +290,16 @@ namespace promise {
{
case State::Pending:
return promise_t([this, on_fulfilled, on_rejected](promise_t npm) {
- callback_t ret;
- gen_on_fulfilled(on_fulfilled, npm, ret);
- add_on_fulfilled(ret);
- gen_on_rejected(on_rejected, npm, ret);
- add_on_rejected(ret);
+ add_on_fulfilled(gen_on_fulfilled(on_fulfilled, npm));
+ add_on_rejected(gen_on_rejected(on_rejected, npm));
});
case State::Fulfilled:
return promise_t([this, on_fulfilled](promise_t npm) {
- callback_t ret;
- gen_on_fulfilled(on_fulfilled, npm, ret);
- ret();
+ gen_on_fulfilled(on_fulfilled, npm)();
});
case State::Rejected:
return promise_t([this, on_rejected](promise_t npm) {
- callback_t ret;
- gen_on_rejected(on_rejected, npm, ret);
- ret();
+ gen_on_rejected(on_rejected, npm)();
});
default: PROMISE_ERR_INVALID_STATE;
}
@@ -236,16 +311,12 @@ namespace promise {
{
case State::Pending:
return promise_t([this, on_fulfilled](promise_t npm) {
- callback_t ret;
- gen_on_fulfilled(on_fulfilled, npm, ret);
- add_on_fulfilled(ret);
+ add_on_fulfilled(gen_on_fulfilled(on_fulfilled, npm));
add_on_rejected([this, npm]() {npm->reject(reason);});
});
case State::Fulfilled:
return promise_t([this, on_fulfilled](promise_t npm) {
- callback_t ret;
- gen_on_fulfilled(on_fulfilled, npm, ret);
- ret();
+ gen_on_fulfilled(on_fulfilled, npm)();
});
case State::Rejected:
return promise_t([this](promise_t npm) {npm->reject(reason);});
@@ -260,47 +331,40 @@ namespace promise {
case State::Pending:
return promise_t([this, on_rejected](promise_t npm) {
callback_t ret;
- gen_on_rejected(on_rejected, npm, ret);
- add_on_rejected(ret);
+ add_on_rejected(gen_on_rejected(on_rejected, npm));
add_on_fulfilled([this, npm]() {npm->resolve(result);});
});
case State::Fulfilled:
return promise_t([this](promise_t npm) {npm->resolve(result);});
case State::Rejected:
return promise_t([this, on_rejected](promise_t npm) {
- callback_t ret;
- gen_on_rejected(on_rejected, npm, ret);
- ret();
+ gen_on_rejected(on_rejected, npm)();
});
default: PROMISE_ERR_INVALID_STATE;
}
}
-
+
+ void resolve() {
+ if (state == State::Pending) trigger_fulfill();
+ }
+
+ void reject() {
+ if (state == State::Pending) trigger_reject();
+ }
+
void resolve(pm_any_t _result) {
- switch (state)
+ if (state == State::Pending)
{
- case State::Pending:
- result = _result;
- state = State::Fulfilled;
- for (const auto &cb: fulfilled_callbacks) cb();
- rejected_callbacks.clear();
- break;
- default:
- break;
+ result = _result;
+ trigger_fulfill();
}
}
void reject(pm_any_t _reason) {
- switch (state)
+ if (state == State::Pending)
{
- case State::Pending:
- reason = _reason;
- state = State::Rejected;
- for (const auto &cb: rejected_callbacks) cb();
- rejected_callbacks.clear();
- break;
- default:
- break;
+ reason = _reason;
+ trigger_reject();
}
}
};
@@ -318,11 +382,9 @@ namespace promise {
(*results)[idx] = result;
if (!--(*size))
npm->resolve(*results);
- return pm_any_t(none);
},
[npm, size](pm_any_t reason) {
npm->reject(reason);
- return pm_any_t(none);
});
idx++;
}
@@ -335,6 +397,9 @@ namespace promise {
template<typename T>
inline void promise_t::reject(T reason) const { (*this)->reject(reason); }
+ inline void promise_t::resolve() const { (*this)->resolve(); }
+ inline void promise_t::reject() const { (*this)->reject(); }
+
template<typename T>
struct callback_types {
using arg_type = typename function_traits<T>::arg_type;
@@ -344,70 +409,60 @@ namespace promise {
};
template<typename Func,
- typename std::enable_if<std::is_same<
- typename function_traits<Func>::ret_type,
- void>::value>::type * = nullptr>
- constexpr auto convert_void_func_(Func f) {
- return [f](typename function_traits<Func>::arg_type v) {
- f(v);
- return none;
+ typename enable_if_return<Func, void>::type * = nullptr,
+ typename function_traits<Func>::non_empty_arg * = nullptr>
+ constexpr auto gen_any_callback(Func f) {
+ using func_t = callback_types<Func>;
+ return [f](pm_any_t v) mutable {
+ try {
+ f(any_cast<typename func_t::arg_type>(v));
+ } catch (bad_any_cast e) { PROMISE_ERR_MISMATCH_TYPE; }
};
}
-
+
template<typename Func,
- typename std::enable_if<!std::is_same<
- typename function_traits<Func>::ret_type,
- void>::value>::type * = nullptr>
- constexpr auto convert_void_func_(Func f) { return f; }
+ typename enable_if_return<Func, void>::type * = nullptr,
+ typename function_traits<Func>::empty_arg * = nullptr>
+ constexpr auto gen_any_callback(Func f) { return f; }
- template<typename Func, typename function_traits<Func>::empty_arg * = nullptr>
- constexpr auto convert_void_func(Func f) { return convert_void_func_([f](None) {f();}); }
+ template<typename Func,
+ typename disable_if_return<Func, void>::type * = nullptr,
+ typename function_traits<Func>::non_empty_arg * = nullptr>
+ constexpr auto gen_any_callback(Func f) {
+ using func_t = callback_types<Func>;
+ return [f](pm_any_t v) mutable {
+ try {
+ return typename func_t::ret_type(
+ f(any_cast<typename func_t::arg_type>(v)));
+ } catch (bad_any_cast e) { PROMISE_ERR_MISMATCH_TYPE; }
+ };
+ }
- template<typename Func, typename function_traits<Func>::non_empty_arg * = nullptr>
- constexpr auto convert_void_func(Func f) { return convert_void_func_(f); }
+ template<typename Func,
+ typename disable_if_return<Func, void>::type * = nullptr,
+ typename function_traits<Func>::empty_arg * = nullptr>
+ constexpr auto gen_any_callback(Func f) {
+ using func_t = callback_types<Func>;
+ return [f]() mutable {
+ return typename func_t::ret_type(f());
+ };
+ }
template<typename FuncFulfilled>
inline promise_t promise_t::then(FuncFulfilled on_fulfilled) const {
- using fulfill_t = callback_types<FuncFulfilled>;
- return (*this)->then(
- [on_fulfilled](pm_any_t _result) mutable {
- try {
- return typename fulfill_t::ret_type(convert_void_func(on_fulfilled)(
- any_cast<typename fulfill_t::arg_type>(_result)));
- } catch (bad_any_cast e) { PROMISE_ERR_MISMATCH_TYPE; }
- });
+ return (*this)->then(gen_any_callback(on_fulfilled));
}
template<typename FuncFulfilled, typename FuncRejected>
inline promise_t promise_t::then(FuncFulfilled on_fulfilled,
FuncRejected on_rejected) const {
- using fulfill_t = callback_types<FuncFulfilled>;
- using reject_t = callback_types<FuncRejected>;
- return (*this)->then(
- [on_fulfilled](pm_any_t _result) mutable {
- try {
- return typename fulfill_t::ret_type(convert_void_func(on_fulfilled)(
- any_cast<typename fulfill_t::arg_type>(_result)));
- } catch (bad_any_cast e) { PROMISE_ERR_MISMATCH_TYPE; }
- },
- [on_rejected](pm_any_t _reason) mutable {
- try {
- return typename reject_t::ret_type(convert_void_func(on_rejected)(
- any_cast<typename reject_t::arg_type>(_reason)));
- } catch (bad_any_cast e) { PROMISE_ERR_MISMATCH_TYPE; }
- });
+ return (*this)->then(gen_any_callback(on_fulfilled),
+ gen_any_callback(on_rejected));
}
template<typename FuncRejected>
inline promise_t promise_t::fail(FuncRejected on_rejected) const {
- using reject_t = callback_types<FuncRejected>;
- return (*this)->fail(
- [on_rejected](pm_any_t _reason) mutable {
- try {
- return typename reject_t::ret_type(convert_void_func(on_rejected)(
- any_cast<typename reject_t::arg_type>(_reason)));
- } catch (bad_any_cast e) { PROMISE_ERR_MISMATCH_TYPE; }
- });
+ return (*this)->fail(gen_any_callback(on_rejected));
}
}
diff --git a/test.cpp b/test.cpp
index 62a07de..f169828 100644
--- a/test.cpp
+++ b/test.cpp
@@ -59,9 +59,12 @@ int main() {
return 12;
}).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");
+ puts("void return is ok");
}).then([]() {
- puts("void parameter will automatically be promise::None");
+ puts("void parameter is ok");
+ return 1;
+ }).then([]() {
+ puts("void parameter will ignore the returned value");
});
auto p1 = promise_t([&t4](promise_t pm) {
@@ -94,7 +97,6 @@ int main() {
})
.then([](const promise::values_t values) {
printf("finally %d\n", any_cast<int>(values[1]));
- return promise::none;
});
puts("calling t");
t4();