Skip to content

Commit

Permalink
妈妈,我看不懂 is_instance_of_v 背后的魔法了
Browse files Browse the repository at this point in the history
  • Loading branch information
microcai committed Oct 18, 2024
1 parent 99ac88c commit 4652ae7
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 16 deletions.
50 changes: 35 additions & 15 deletions include/ucoro/awaitable.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,18 +73,33 @@ namespace ucoro
template<typename T>
struct local_storage_t
{
typedef T value_type;
typedef void local_storage_type_detect_tag;
};

inline constexpr local_storage_t<void> local_storage;

template <typename T>
concept is_a_local_storage_t = std::is_same_v<typename T::local_storage_type_detect_tag, typename T::local_storage_type_detect_tag>;

//////////////////////////////////////////////////////////////////////////
namespace detail
{

// 用于判定 T 是否是一个 U<anytype> 的类型
// 比如
// is_instance_of_v<std::vector<int>,std::vector>; // true
// is_instance_of_v<std::vector<int>,std::list>; // false
template<class T, template<class...> class U>
inline constexpr bool is_instance_of_v = std::false_type{};

template<template<class...> class U, class... Vs>
inline constexpr bool is_instance_of_v<U<Vs...>,U> = std::true_type{};

template<class LocalStorage>
struct local_storage_value_type;

template<class ValueType>
struct local_storage_value_type<local_storage_t<ValueType>>
{
typedef ValueType value_type;
};

template<typename T>
concept is_valid_await_suspend_return_value =
std::convertible_to<T, std::coroutine_handle<>> || std::is_void_v<T> || std::is_same_v<T, bool>;
Expand All @@ -106,11 +121,7 @@ namespace ucoro
template<typename T>
concept is_awaitable_v = is_awaiter_v<T> || has_operator_co_await<T>;

// 用于判定 T 是否是一个 awaitable<>::promise_type 的类型, 即: 拥有 local_ 成员。
template<typename T>
concept is_awaitable_promise_type_v = requires (T a) {
{ a.local_ } -> std::convertible_to<std::shared_ptr<std::any>>;
};

} // namespace detail

struct debug_coro_promise
Expand Down Expand Up @@ -266,16 +277,24 @@ namespace ucoro
template<typename A>
auto await_transform(A&& awaiter) const
{
if constexpr ( is_a_local_storage_t<std::decay_t<A>> )
if constexpr (detail::is_instance_of_v<std::decay_t<A>, local_storage_t>)
{
return local_storage_awaiter<typename std::decay_t<A>::value_type>{this};
// 类型 A 是 local_storage_t<> 的一种
return local_storage_awaiter<typename detail::local_storage_value_type<std::decay_t<A>>::value_type>{this};
}
else if constexpr (detail::is_instance_of_v<std::decay_t<A>, awaitable>)
{
// 类型 A 是 awaitable<> 的一种
static_assert(std::is_rvalue_reference_v<decltype(awaiter)>, "co_await must be used on rvalue");
return std::forward<A>(awaiter);
}
else if constexpr ( detail::is_awaitable_v<std::decay_t<A>> )
else if constexpr (detail::is_awaitable_v<std::decay_t<A>>)
{
// 类型 A 有 三件套
static_assert(std::is_rvalue_reference_v<decltype(awaiter)>, "co_await must be used on rvalue");
return std::forward<A>(awaiter);
}
else if constexpr ( requires (A ) { await_transformer<A>::await_transform; })
else if constexpr (requires (A) { await_transformer<A>::await_transform; })
{
return await_transformer<A>::await_transform(std::move(awaiter));
}
Expand Down Expand Up @@ -397,7 +416,8 @@ namespace ucoro
template<typename PromiseType>
auto await_suspend(std::coroutine_handle<PromiseType> continuation)
{
if constexpr (detail::is_awaitable_promise_type_v<PromiseType>)
// PromiseType 是 awaitable<any>::promise_type 的一种
if constexpr (detail::is_instance_of_v<PromiseType, awaitable_promise>)
{
auto& calee_promise = this_->current_coro_handle_.promise();
auto& caller_promise = continuation.promise();
Expand Down
2 changes: 1 addition & 1 deletion tests/test3/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ int main(int argc, char **argv)
using CallbackAwaiterType0 = ucoro::CallbackAwaiter<void, decltype([](auto h) {}) >;
using CallbackAwaiterType1 = ucoro::CallbackAwaiter<int, decltype([](auto h) {}) > ;

static_assert(ucoro::is_a_local_storage_t<ucoro::local_storage_t<void>>, "not a local_storage_t");
static_assert(ucoro::detail::is_instance_of_v<ucoro::local_storage_t<void>, ucoro::local_storage_t>, "not a local_storage_t");

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

0 comments on commit 4652ae7

Please sign in to comment.