#ifndef _CPPROMISE_HPP
#define _CPPROMISE_HPP
/**
* MIT License
* Copyright (c) 2018 Ted Yin <tederminant@gmail.com>
*
* 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 <stack>
#include <vector>
#include <memory>
#include <functional>
#include <type_traits>
#if __cplusplus >= 201703L
#ifdef __has_include
# if __has_include(<any>)
# include <any>
# ifdef __cpp_lib_any
# define _CPPROMISE_STD_ANY
# endif
# endif
#endif
#endif
#ifndef _CPPROMISE_STD_ANY
#include <boost/any.hpp>
#endif
/**
* Implement type-safe Promise primitives similar to the ones specified by
* Javascript Promise/A+.
*/
namespace promise {
#ifdef _CPPROMISE_STD_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 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
using callback_t = std::function<void()>;
using values_t = std::vector<pm_any_t>;
/* match lambdas */
template<typename T>
struct function_traits:
public function_traits<decltype(&T::operator())> {};
template<typename ReturnType>
struct function_traits<ReturnType()> {
using ret_type = ReturnType;
using arg_type = void;
using empty_arg = void;
};
/* match plain functions */
template<typename ReturnType, typename ArgType>
struct function_traits<ReturnType(ArgType)> {
using ret_type = ReturnType;
using arg_type = ArgType;
using non_empty_arg = void;
};
/* match function pointers */
template<typename ReturnType, typename... ArgType>
struct function_traits<ReturnType(*)(ArgType...)>:
public function_traits<ReturnType(ArgType...)> {};
/* match const member functions */
template<typename ClassType, typename ReturnType, typename... ArgType>
struct function_traits<ReturnType(ClassType::*)(ArgType...) const>:
public function_traits<ReturnType(ArgType...)> {};
/* match member functions */
template<typename ClassType, typename ReturnType, typename... ArgType>
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>;
template<typename Func, typename ArgType>
using enable_if_arg = typename std::enable_if<
std::is_same<typename function_traits<Func>::arg_type,
ArgType>::value>;
template<typename Func, typename ArgType>
using disable_if_arg = typename std::enable_if<
!std::is_same<typename function_traits<Func>::arg_type,
ArgType>::value>;
class Promise;
//class promise_t: public std::shared_ptr<Promise> {
class promise_t {
Promise *pm;
size_t *ref_cnt;
public:
friend Promise;
template<typename PList> friend promise_t all(const PList &promise_list);
template<typename PList> friend promise_t race(const PList &promise_list);
inline promise_t();
inline ~promise_t();
template<typename Func> inline promise_t(Func callback);
void swap(promise_t &other) {
std::swap(pm, other.pm);
std::swap(ref_cnt, other.ref_cnt);
}
promise_t &operator=(const promise_t &other) {
if (this != &other)
{
promise_t tmp(other);
tmp.swap(*this);
}
return *this;
}
promise_t &operator=(promise_t &&other) {
if (this != &other)
{
promise_t tmp(std::move(other));
tmp.swap(*this);
}
return *this;
}
promise_t(const promise_t &other):
pm(other.pm),
ref_cnt(other.ref_cnt) {
++*ref_cnt;
}
promise_t(promise_t &&other):
pm(other.pm),
ref_cnt(other.ref_cnt) {
other.pm = nullptr;
}
Promise *operator->() const {
return pm;
}
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;
template<typename FuncFulfilled, typename FuncRejected>
inline promise_t then(FuncFulfilled on_fulfilled,