Skip to content

Commit

Permalink
本更新主要为 local_storage 使用便利,共3处大更新:
Browse files Browse the repository at this point in the history
1,添加 is_awaiter_v 模板用于 await_transform 模板参数判断

2,增加 local_storage_t 的用法,例如:

auto y = co_await ucoro::local_storage_t<std::string>();

通过 ucoro::local_storage_t 模板类型返回它本身的类型,这样就不必自己做 std::any_cast 了

3,添加对 is_awaiter_v 模板的测试用例。
  • Loading branch information
Jackarain committed Oct 2, 2024
1 parent c45f41c commit 4206282
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 5 deletions.
84 changes: 79 additions & 5 deletions include/ucoro/awaitable.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,57 @@ namespace ucoro
template <typename T, typename CallbackFunction>
struct CallbackAwaiter;

template <typename T>
struct local_storage_t {};
inline constexpr local_storage_t local_storage;
inline constexpr local_storage_t<void> local_storage;


//////////////////////////////////////////////////////////////////////////
/// is_awaiter from https://github.com/lewissbaker/cppcoro/blob/master/include/cppcoro/detail/is_awaiter.hpp
namespace detail
{
template<typename T>
struct is_coroutine_handle
: std::false_type
{};

template<typename PROMISE>
struct is_coroutine_handle<std::coroutine_handle<PROMISE>>
: std::true_type
{};

// NOTE: We're accepting a return value of coroutine_handle<P> here
// which is an extension supported by Clang which is not yet part of
// the C++ coroutines TS.
template<typename T>
struct is_valid_await_suspend_return_value : std::disjunction<
std::is_void<T>,
std::is_same<T, bool>,
is_coroutine_handle<T>>
{};

template<typename T, typename = std::void_t<>>
struct is_awaiter : std::false_type {};

// NOTE: We're testing whether await_suspend() will be callable using an
// arbitrary coroutine_handle here by checking if it supports being passed
// a coroutine_handle<void>. This may result in a false-result for some
// types which are only awaitable within a certain context.
template<typename T>
struct is_awaiter<T, std::void_t<
decltype(std::declval<T>().await_ready()),
decltype(std::declval<T>().await_suspend(std::declval<std::coroutine_handle<>>())),
decltype(std::declval<T>().await_resume())>> :
std::conjunction<
std::is_constructible<bool, decltype(std::declval<T>().await_ready())>,
is_valid_await_suspend_return_value<
decltype(std::declval<T>().await_suspend(std::declval<std::coroutine_handle<>>()))>>
{};

template <typename T>
constexpr bool is_awaiter_v = is_awaiter<T>::value;
} // namespace detail


//////////////////////////////////////////////////////////////////////////
struct awaitable_detached
Expand Down Expand Up @@ -118,13 +167,13 @@ namespace ucoro

void unhandled_exception() {}

template <typename A>
template <typename A, typename std::enable_if<detail::is_awaiter_v<A>>::type* = nullptr>
auto await_transform(A awaiter) const
{
return awaiter;
}

auto await_transform(local_storage_t) noexcept
auto await_transform(local_storage_t<void>) noexcept
{
struct result
{
Expand All @@ -145,7 +194,32 @@ namespace ucoro
}
};

return result{this};
return result{ this };
}

template <typename T>
auto await_transform(local_storage_t<T>)
{
struct result
{
awaitable_promise_base* this_;

bool await_ready() const noexcept
{
return true;
}

void await_suspend(std::coroutine_handle<void>) noexcept
{
}

auto await_resume()
{
return std::any_cast<T>(*this_->local_);
}
};

return result{ this };
}

std::coroutine_handle<> continuation_;
Expand Down Expand Up @@ -408,7 +482,7 @@ struct CallbackAwaiter<void, CallbackFunction>

auto await_suspend(std::coroutine_handle<> handle)
{
callback_function_([this]() {});
callback_function_([]() {});
return handle;
}

Expand Down
10 changes: 10 additions & 0 deletions tests/test1/test1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,16 @@ ucoro::awaitable<void> coro_compute_exec(int value)
auto x = co_await ucoro::local_storage;
std::cout << "local storage: " << std::any_cast<std::string>(x) << std::endl;

try
{
auto y = co_await ucoro::local_storage_t<std::string>();
std::cout << "local storage: " << y << std::endl;
}
catch (const std::exception& e)
{
std::cout << e.what();
}

auto ret = co_await coro_compute_int(value);
std::cout << "return: " << ret << std::endl;
co_return;
Expand Down
6 changes: 6 additions & 0 deletions tests/test3/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@

add_executable(test3 test.cpp)
target_link_libraries(test3 ucoro)

add_test(NAME test3 COMMAND test3)
set_target_properties(test3 PROPERTIES FOLDER "ucoro_tests")
25 changes: 25 additions & 0 deletions tests/test3/test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#include <iostream>
#include "ucoro/awaitable.hpp"


int main(int argc, char **argv)
{
using CallbackAwaiterType0 = CallbackAwaiter<void, decltype([](auto h) {}) >;
using ExecutorAwaiterType0 = ExecutorAwaiter<void, decltype([](auto h) {}) > ;

using CallbackAwaiterType1 = CallbackAwaiter<int, decltype([](auto h) {}) > ;
using ExecutorAwaiterType1 = ExecutorAwaiter<int, decltype([](auto h) {}) > ;

static_assert(ucoro::detail::is_awaiter_v < CallbackAwaiterType0 >, "not a coroutine");
static_assert(ucoro::detail::is_awaiter_v < ExecutorAwaiterType0 >, "not a coroutine");

static_assert(ucoro::detail::is_awaiter_v < CallbackAwaiterType1 >, "not a coroutine");
static_assert(ucoro::detail::is_awaiter_v < ExecutorAwaiterType1 >, "not a coroutine");

static_assert(ucoro::detail::is_awaiter_v < ucoro::awaitable<void> >, "not a coroutine");
static_assert(ucoro::detail::is_awaiter_v < ucoro::awaitable<int> >, "not a coroutine");

static_assert(!ucoro::detail::is_awaiter_v < int >, "not a coroutine");

return 0;
}

0 comments on commit 4206282

Please sign in to comment.