Last active
July 12, 2016 05:21
-
-
Save sayurin/7232bdc946c5c3794df880ffd4057e39 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <future> | |
#ifdef USE_AWAIT | |
#include <experimental/resumable> | |
#include <boost/asio/use_future.hpp> | |
#else | |
#include <exception> | |
#include <memory> | |
#include <type_traits> | |
#include <utility> | |
#include <boost/asio/spawn.hpp> | |
#define co_await | |
#endif | |
namespace coroutine { | |
namespace detail { | |
#ifdef USE_AWAIT | |
using handler = boost::asio::use_future_t<>; | |
template<class Result> using result = std::future<Result>; | |
template<class Context, class... Args> | |
inline auto spawn(Context&&, Args&&... args) -> decltype(std::invoke(std::forward<Args>(args)..., boost::asio::use_future)) { | |
return std::invoke(std::forward<Args>(args)..., boost::asio::use_future); | |
} | |
#else | |
using handler = boost::asio::yield_context; | |
template<class Result> using result = Result; | |
template<class Tuple, std::size_t... Index> | |
inline void invoke_and_set(Tuple&& tuple, boost::asio::yield_context& handler, std::promise<void>& promise, std::index_sequence<Index...>) { | |
std::invoke(std::get<Index>(std::forward<Tuple>(tuple))..., handler); | |
promise.set_value(); | |
} | |
template<class Tuple, class Result, std::size_t... Index> | |
inline void invoke_and_set(Tuple&& tuple, boost::asio::yield_context& handler, std::promise<Result>& promise, std::index_sequence<Index...>) { | |
auto result = std::invoke(std::get<Index>(std::forward<Tuple>(tuple))..., handler); | |
promise.set_value(result); | |
} | |
template<class Context, class... Args> | |
inline auto spawn(Context&& context, Args&&... args) { | |
auto promise = std::make_unique<std::promise<decltype(std::invoke(args..., std::declval<boost::asio::yield_context>()))>>(); | |
auto future = promise->get_future(); | |
boost::asio::spawn(std::forward<Context>(context), [tuple = std::forward_as_tuple(args...), promise = std::move(promise)](auto handler) { | |
try { | |
detail::invoke_and_set(std::forward<std::tuple<Args...>>(tuple), handler, *promise, std::index_sequence_for<Args...>{}); | |
} | |
catch (...) { | |
promise->set_exception(std::current_exception()); | |
} | |
}); | |
return future; | |
} | |
#endif | |
} | |
// coroutine::invoke()が呼び出せるコルーチンの引数型 | |
using handler = detail::handler; | |
// coroutine::invoke()が呼び出せるコルーチンの戻り値型 | |
template<class Result> using result = detail::result<Result>; | |
/// <summary>コルーチンを呼び出します。</summary> | |
/// <param name="context">boost::asio::spawn()の第1引数となるため、boost::asio::io_service& / boost::asio::io_service::strandなど</param> | |
/// <param name="callable">呼び出すコルーチン、引数はargs...の後にcoroutine::handler、戻り値はcoroutine::result<Result></param> | |
/// <param name="args">呼び出すコルーチンの引数</param> | |
/// <returns>std::future<Result>になります。</returns> | |
template<class Context, class Callable, class... Args> | |
inline decltype(auto) spawn(Context&& context, Callable&& callable, Args&&... args) { | |
return detail::spawn(std::forward<Context>(context), std::forward<Callable>(callable), std::forward<Args>(args)...); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define _WIN32_WINDOWS _WIN32_WINDOWS_WIN7 | |
#define _WINSOCK_DEPRECATED_NO_WARNINGS | |
#define BOOST_DATE_TIME_NO_LIB | |
#define BOOST_ERROR_CODE_HEADER_ONLY | |
#define BOOST_REGEX_NO_LIB | |
#define BOOST_SYSTEM_NO_LIB | |
#include <iostream> | |
#include <thread> | |
#include <boost/asio/io_service.hpp> | |
#include <boost/asio/ip/tcp.hpp> | |
using boost::asio::io_service; | |
using boost::asio::ip::tcp; | |
#include "coroutine.h" | |
coroutine::result<int> run(io_service& ios, coroutine::handler handler) { | |
tcp::resolver resolver{ ios }; | |
auto itor = co_await resolver.async_resolve(tcp::resolver::query{ "www.google.com", "http" }, handler); | |
int count = 0; | |
for (tcp::resolver::iterator end; itor != end; ++itor, ++count) | |
std::cout << itor->endpoint() << std::endl; | |
return count; | |
} | |
int main() { | |
io_service ios; | |
io_service::work work{ ios }; | |
std::thread thread{ [&] { ios.run(); } }; | |
auto result = coroutine::spawn(ios, run, ios); | |
std::cout << "spawned." << std::endl; | |
auto count = result.get(); | |
std::cout << "completed, result count =" << count << std::endl; | |
ios.stop(); | |
thread.join(); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment