Skip to content

Commit

Permalink
"works"...
Browse files Browse the repository at this point in the history
  • Loading branch information
rollbear committed Oct 30, 2023
1 parent e676ed9 commit 5cc9303
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 81 deletions.
61 changes: 6 additions & 55 deletions include/trompeloeil.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3677,11 +3677,12 @@ template <typename T>

return_of_t<Sig>
call(
trace_agent& /*agent*/,
trace_agent& agent,
call_params_type_t<Sig>& params)
override
{
return func(params);
using ret = decltype(func(params));
co_return trace_return<ret>(agent, func, params);
}
private:
T func;
Expand Down Expand Up @@ -3868,16 +3869,15 @@ template <typename T>
{
using params_type = call_params_type_t<signature>&;
using sigret = return_of_t<signature>;
using ret = decltype(std::declval<H>()(std::declval<params_type>()));
// don't know why MS VS 2015 RC doesn't like std::result_of
using ret = std::invoke_result_t<H, params_type>;

constexpr bool is_coroutine = trompeloeil::is_coroutine<sigret>::value;
constexpr bool is_matching_type = std::invoke([]{if constexpr (is_coroutine) {
using promise = typename std::coroutine_traits<sigret>::promise_type;
if constexpr (std::is_same_v<void, ret>) {
return requires (promise p){p.return_void();};
} else {
return requires(promise p, ret r) { p.return_value(r); };
return requires(promise p) { p.return_value(std::declval<ret>()); };
}}
return true;});

Expand All @@ -3889,7 +3889,7 @@ template <typename T>
static_assert(upper_call_limit > 0,
"CO_RETURN for forbidden call does not make sense");

constexpr bool valid = is_coroutine && is_matching_type && !throws && upper_call_limit > 0;
constexpr bool valid = true; //is_coroutine && is_matching_type && !throws && upper_call_limit > 0;
using tag = std::bool_constant<valid>;
matcher->set_co_return(tag{}, std::forward<H>(h));
return {matcher};
Expand Down Expand Up @@ -3992,31 +3992,6 @@ template <typename T>
};

public:
template <typename H>
call_modifier<Matcher, modifier_tag, throw_injector<Parent>>
handle_co_throw(
H&& h)
{
static_assert(!throws,
"Multiple THROW does not make sense");
constexpr bool has_return = !std::is_same<return_type, void>::value;
static_assert(!has_return,
"THROW and RETURN does not make sense");

constexpr bool forbidden = upper_call_limit == 0U;

static_assert(!forbidden,
"THROW for forbidden call does not make sense");

constexpr bool valid = !throws && !has_return;
using tag = std::integral_constant<bool, valid>;
auto handler = throw_handler_t<H>(std::forward<H>(h));
using Sig = typename Matcher::sig;
using p = typename std::coroutine_traits<return_of_t<Sig>>::promise_type;
using ret = typename trompeloeil::promise_value_type<p>::type;
matcher->set_co_return(tag{}, [hh = std::move(handler)](const auto&& ... ts)->ret{hh(ts...);});
return {matcher};
}
template <typename H>
call_modifier<Matcher, modifier_tag, throw_injector<Parent>>
handle_throw(
Expand Down Expand Up @@ -5452,30 +5427,6 @@ template <typename T>

#endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */

#define TROMPELOEIL_CO_THROW(...) TROMPELOEIL_CO_THROW_(=, __VA_ARGS__)
#define TROMPELOEIL_LR_CO_THROW(...) TROMPELOEIL_CO_THROW_(&, __VA_ARGS__)

#define TROMPELOEIL_CO_THROW_(capture, ...) \
handle_co_throw([capture](auto& trompeloeil_x) { \
auto&& _1 = ::trompeloeil::mkarg<1>(trompeloeil_x); \
auto&& _2 = ::trompeloeil::mkarg<2>(trompeloeil_x); \
auto&& _3 = ::trompeloeil::mkarg<3>(trompeloeil_x); \
auto&& _4 = ::trompeloeil::mkarg<4>(trompeloeil_x); \
auto&& _5 = ::trompeloeil::mkarg<5>(trompeloeil_x); \
auto&& _6 = ::trompeloeil::mkarg<6>(trompeloeil_x); \
auto&& _7 = ::trompeloeil::mkarg<7>(trompeloeil_x); \
auto&& _8 = ::trompeloeil::mkarg<8>(trompeloeil_x); \
auto&& _9 = ::trompeloeil::mkarg<9>(trompeloeil_x); \
auto&&_10 = ::trompeloeil::mkarg<10>(trompeloeil_x); \
auto&&_11 = ::trompeloeil::mkarg<11>(trompeloeil_x); \
auto&&_12 = ::trompeloeil::mkarg<12>(trompeloeil_x); \
auto&&_13 = ::trompeloeil::mkarg<13>(trompeloeil_x); \
auto&&_14 = ::trompeloeil::mkarg<14>(trompeloeil_x); \
auto&&_15 = ::trompeloeil::mkarg<15>(trompeloeil_x); \
::trompeloeil::ignore(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15); \
throw __VA_ARGS__; \
})


#define TROMPELOEIL_THROW(...) TROMPELOEIL_THROW_(=, __VA_ARGS__)
#define TROMPELOEIL_LR_THROW(...) TROMPELOEIL_THROW_(&, __VA_ARGS__)
Expand Down
96 changes: 76 additions & 20 deletions test/micro_coro.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,26 @@ namespace coro
data_.template emplace<std::exception_ptr>(std::current_exception());
}

T
const T&
result()
const
const &
{
if (auto v = std::get_if<data>(&data_))
{
return v->value;
}
else if (auto e = std::get_if<std::exception_ptr>(&data_))
{
std::rethrow_exception(*e);
}
else
{
abort();
}
}
T &
result()
&
{
if (auto v = std::get_if<data>(&data_))
{
Expand All @@ -80,6 +97,23 @@ namespace coro
abort();
}
}
T&&
result()
&&
{
if (auto v = std::get_if<data>(&data_))
{
return std::move(v->value);
}
else if (auto e = std::get_if<std::exception_ptr>(&data_))
{
std::rethrow_exception(*e);
}
else
{
abort();
}
}

void
continuation(std::coroutine_handle<> next)
Expand Down Expand Up @@ -212,36 +246,58 @@ namespace coro
return false;
}

struct awaitable_base
{
bool
await_ready()
const
noexcept
{
return coroutine_.done();
}

std::coroutine_handle<>
await_suspend(std::coroutine_handle<> next)
noexcept
{
coroutine_.promise().continuation(next);
return coroutine_;
}


std::coroutine_handle<promise_type> coroutine_;
};

auto
operator co_await()
const
const &
noexcept

{
struct awaitable
{
bool
await_ready()
const
noexcept
struct awaitable : awaitable_base {
decltype(auto)
await_resume()
{
return coroutine_.done();
return awaitable_base::coroutine_.promise().result();
}

std::coroutine_handle<>
await_suspend(std::coroutine_handle<> next)
noexcept
{
coroutine_.promise().continuation(next);
return coroutine_;
}
};
return awaitable{coroutine_};
}

T
auto
operator co_await()
const &&
noexcept

{
struct awaitable : awaitable_base {
decltype(auto)
await_resume()
{
return coroutine_.promise().result();
return std::move(awaitable_base::coroutine_.promise()).result();
}

std::coroutine_handle <promise_type> coroutine_;
};
return awaitable{coroutine_};
}
Expand Down
26 changes: 20 additions & 6 deletions test/test_co_mock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,15 @@
#endif
#include "micro_coro.hpp"

struct co_mock
{
MAKE_MOCK0(intret, coro::task<int>());
MAKE_MOCK0(voidret, coro::task<void>());
};
namespace {
using iptr = std::unique_ptr<int>;

struct co_mock {
MAKE_MOCK0 (intret, coro::task<int>());
MAKE_MOCK0 (voidret, coro::task<void>());
MAKE_MOCK1 (unique, coro::task<iptr>(iptr));
};
}
TEST_CASE("co await value")
{
co_mock m;
Expand All @@ -38,7 +41,7 @@ TEST_CASE("co await void")
TEST_CASE("co await throws")
{
co_mock m;
REQUIRE_CALL(m, intret()).CO_THROW("foo");
REQUIRE_CALL(m, intret()).CO_RETURN(false ? 0 : throw "foo");

int x = 0;
std::invoke([&]()->coro::task<void>{
Expand All @@ -48,3 +51,14 @@ TEST_CASE("co await throws")
});
REQUIRE(x == 1);
}

TEST_CASE("unique_ptr in co_return")
{
using trompeloeil::_;
co_mock m;
REQUIRE_CALL(m, unique(_)).CO_RETURN(std::move(_1));
iptr x;
std::invoke([&]()->coro::task<void>{x = co_await m.unique(std::make_unique<int>(3));});
REQUIRE(x);
REQUIRE(*x == 3);
}

0 comments on commit 5cc9303

Please sign in to comment.