diff options
-rw-r--r-- | Makefile | 8 | ||||
-rw-r--r-- | promise.hpp | 107 | ||||
-rw-r--r-- | test.cpp | 9 |
3 files changed, 70 insertions, 54 deletions
@@ -1,2 +1,6 @@ -test: test.cpp promise.hpp - g++ -o test test.cpp -std=c++17 +.PHONY: all +all: test14 test17 +test14: test.cpp promise.hpp + g++ -o $@ test.cpp -std=c++17 +test17: test.cpp promise.hpp + g++ -o $@ test.cpp -std=c++14 diff --git a/promise.hpp b/promise.hpp index 0f9198c..25fbd3b 100644 --- a/promise.hpp +++ b/promise.hpp @@ -1,16 +1,61 @@ #ifndef _CPPROMISE_HPP #define _CPPROMISE_HPP +/** + * MIT License + * Copyright (c) 2018 Ted Yin <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + #include <vector> #include <memory> -#include <any> #include <functional> -/** Implement type-safe Promise primitives similar to the ones specified by - * Javascript A+. */ +#if __has_include("any") +#include <any> +#endif + +#if !defined(__cpp_lib_any) +#include <boost/any.hpp> +#endif + +/** + * Implement type-safe Promise primitives similar to the ones specified by + * Javascript Promise/A+. + */ namespace promise { using std::function; + +#if defined(__cpp_lib_any) using pm_any_t = std::any; + template<typename T> + 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" + 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 + using None = std::nullptr_t; using values_t = std::vector<pm_any_t>; const auto none = nullptr; @@ -82,8 +127,6 @@ namespace promise { #define PROMISE_ERR_MISMATCH_TYPE do {throw std::runtime_error("mismatching promise value types");} while (0) class Promise { - //function<void()> fulfilled_callback; - //function<void()> rejected_callback; std::vector<function<void()>> fulfilled_callbacks; std::vector<function<void()>> rejected_callbacks; enum class State { @@ -94,27 +137,6 @@ namespace promise { pm_any_t result; pm_any_t reason; - /* this implementation causes stack overflow because of the nested lambdas */ - /* - void add_on_fulfilled(function<void()> cb) { - auto old_cbs = fulfilled_callback; - fulfilled_callback = function<void()>( - [cb, old_cbs]() { - old_cbs(); - cb(); - }); - } - - void add_on_rejected(function<void()> cb) { - auto old_cbs = rejected_callback; - rejected_callback = function<void()>( - [cb, old_cbs]() { - old_cbs(); - cb(); - }); - } - */ - void add_on_fulfilled(function<void()> cb) { fulfilled_callbacks.push_back(cb); } @@ -181,18 +203,8 @@ namespace promise { public: - Promise(): - /* - fulfilled_callback(do_nothing), - rejected_callback(do_nothing), - */ - state(State::Pending) { - //printf("%lx constructed\n", (uintptr_t)this); - } - - ~Promise() { - //printf("%lx freed\n", (uintptr_t)this); - } + Promise(): state(State::Pending) {} + ~Promise() {} template<typename FuncFulfilled, typename FuncRejected> promise_t then(FuncFulfilled on_fulfilled, @@ -275,7 +287,6 @@ namespace promise { case State::Pending: result = _result; state = State::Fulfilled; - //fulfilled_callback(); for (const auto &cb: fulfilled_callbacks) cb(); rejected_callbacks.clear(); break; @@ -290,7 +301,6 @@ namespace promise { case State::Pending: reason = _reason; state = State::Rejected; - //rejected_callback(); for (const auto &cb: rejected_callbacks) cb(); rejected_callbacks.clear(); break; @@ -369,8 +379,8 @@ namespace promise { return ptr->then( [on_fulfilled](pm_any_t _result) mutable { try { - return ret_type(on_fulfilled(std::any_cast<arg_type>(_result))); - } catch (std::bad_any_cast e) { PROMISE_ERR_MISMATCH_TYPE; } + return ret_type(on_fulfilled(any_cast<arg_type>(_result))); + } catch (bad_any_cast e) { PROMISE_ERR_MISMATCH_TYPE; } }); } @@ -384,13 +394,13 @@ namespace promise { return ptr->then( [on_fulfilled](pm_any_t _result) mutable { try { - return fulfill_ret_type(on_fulfilled(std::any_cast<fulfill_arg_type>(_result))); - } catch (std::bad_any_cast e) { PROMISE_ERR_MISMATCH_TYPE; } + return fulfill_ret_type(on_fulfilled(any_cast<fulfill_arg_type>(_result))); + } catch (bad_any_cast e) { PROMISE_ERR_MISMATCH_TYPE; } }, [on_rejected](pm_any_t _reason) mutable { try { - return reject_ret_type(on_rejected(std::any_cast<reject_arg_type>(_reason))); - } catch (std::bad_any_cast e) { PROMISE_ERR_MISMATCH_TYPE; } + return reject_ret_type(on_rejected(any_cast<reject_arg_type>(_reason))); + } catch (bad_any_cast e) { PROMISE_ERR_MISMATCH_TYPE; } }); } @@ -401,9 +411,10 @@ namespace promise { return ptr->fail( [on_rejected](pm_any_t _reason) mutable { try { - return ret_type(on_rejected(std::any_cast<arg_type>(_reason))); - } catch (std::bad_any_cast e) { PROMISE_ERR_MISMATCH_TYPE; } + return ret_type(on_rejected(any_cast<arg_type>(_reason))); + } catch (bad_any_cast e) { PROMISE_ERR_MISMATCH_TYPE; } }); } } + #endif @@ -1,6 +1,7 @@ #include <string> #include "promise.hpp" using promise::promise_t; +using promise::any_cast; struct A { int operator()(int x) { @@ -75,9 +76,9 @@ int main() { auto p4 = promise::all(std::vector<promise_t>{p1, p2, p3}) .then([](const promise::values_t values) { - printf("%d %s %s\n", std::any_cast<int>(values[0]), - std::any_cast<std::string>(values[1]).c_str(), - std::any_cast<std::string>(values[2]).c_str()); + printf("%d %s %s\n", any_cast<int>(values[0]), + any_cast<std::string>(values[1]).c_str(), + any_cast<std::string>(values[2]).c_str()); return 100; }); @@ -87,7 +88,7 @@ int main() { return reason; }) .then([](const promise::values_t values) { - printf("finally %d\n", std::any_cast<int>(values[1])); + printf("finally %d\n", any_cast<int>(values[1])); return promise::none; }); puts("calling t"); |