Browse Source

重新实现when_all/when_any

tags/v2.9.7
tearshark 4 years ago
parent
commit
aba74aaa19

+ 1
- 1
librf/librf.h View File

@@ -45,6 +45,7 @@
#include "src/future.h"
#include "src/promise.h"
#include "src/awaitable.h"
#include "src/generator.h"
#include "src/rf_task.h"
#include "src/utils.h"
@@ -64,6 +65,5 @@
#include "src/channel.h"
#include "src/event.h"
#include "src/generator.h"
#include "src/sleep.h"
#include "src/when.h"

+ 2
- 5
librf/src/event_v2.inl View File

@@ -6,9 +6,6 @@ RESUMEF_NS
{
struct state_event_t;
//仿照cppcoro的event是行不通的。
//虽然cppcoro的event的触发和等待之间是线程安全的,但是并不能实现只触发指定数量。并且多线程触发之间是不安全的。
//所以,还得用锁结构来实现(等待实现,今日不空)。
struct event_v2_impl : public std::enable_shared_from_this<event_v2_impl>
{
event_v2_impl(bool initially) noexcept;
@@ -138,7 +135,7 @@ RESUMEF_NS
{
scoped_lock<detail::event_v2_impl::lock_type> lock_(_event->_lock);
if (_event->try_wait_one())
if ((_value = _event->try_wait_one()) != false)
return false;
_state = new detail::state_event_t(_value);
@@ -187,7 +184,7 @@ RESUMEF_NS
{
scoped_lock<detail::event_v2_impl::lock_type> lock_(_event->_lock);
if (_event->try_wait_one())
if ((_value = _event->try_wait_one()) != false)
return false;
_state = new detail::state_event_t(_value);

+ 12
- 11
librf/src/rf_task.h View File

@@ -19,23 +19,23 @@ RESUMEF_NS
//----------------------------------------------------------------------------------------------
template<class _Ty>
template<class _Ty, class = std::void_t<>>
struct task_t;
template<class _Ty>
struct task_t<future_t<_Ty>> : public task_base_t
struct task_t<_Ty, std::void_t<is_future<std::remove_reference_t<_Ty>>>> : public task_base_t
{
using value_type = _Ty;
using future_type = future_t<value_type>;
using future_type = std::remove_reference_t<_Ty>;
using value_type = typename future_type::value_type;
using state_type = state_t<value_type>;
task_t() = default;
task_t(future_type&& f)
task_t(future_type& f)
{
initialize(std::forward<future_type>(f));
initialize(f);
}
protected:
void initialize(future_type&& f)
void initialize(future_type& f)
{
_state = f._state.get();
}
@@ -49,12 +49,12 @@ RESUMEF_NS
using state_type = state_generator_t;
task_t() = default;
task_t(future_type&& f)
task_t(future_type& f)
{
initialize(std::forward<future_type>(f));
initialize(f);
}
protected:
void initialize(future_type&& f)
void initialize(future_type& f)
{
_state = f.detach_state();
}
@@ -75,7 +75,8 @@ RESUMEF_NS
ctx_task_t(context_type ctx)
: _context(std::move(ctx))
{
this->initialize(_context());
decltype(auto) f = _context();
this->initialize(f);
}
};
}

+ 2
- 2
librf/src/scheduler.h View File

@@ -34,9 +34,9 @@ RESUMEF_NS
inline void operator + (_Ty&& t_)
{
if constexpr (is_callable_v<_Ty>)
new_task(new ctx_task_t<_Ty>(std::forward<_Ty>(t_)));
new_task(new ctx_task_t<_Ty>(t_));
else
new_task(new task_t<_Ty>(std::forward<_Ty>(t_)));
new_task(new task_t<_Ty>(t_));
}
inline bool empty() const

+ 7
- 7
librf/src/switch_scheduler.h View File

@@ -2,15 +2,15 @@

RESUMEF_NS
{
struct switch_scheduler_t
struct switch_scheduler_awaitor
{
switch_scheduler_t(scheduler_t* sch)
switch_scheduler_awaitor(scheduler_t* sch)
:_scheduler(sch) {}
switch_scheduler_t(const switch_scheduler_t&) = default;
switch_scheduler_t(switch_scheduler_t&&) = default;
switch_scheduler_awaitor(const switch_scheduler_awaitor&) = default;
switch_scheduler_awaitor(switch_scheduler_awaitor&&) = default;

switch_scheduler_t& operator = (const switch_scheduler_t&) = default;
switch_scheduler_t& operator = (switch_scheduler_t&&) = default;
switch_scheduler_awaitor& operator = (const switch_scheduler_awaitor&) = default;
switch_scheduler_awaitor& operator = (switch_scheduler_awaitor&&) = default;

bool await_ready() noexcept
{
@@ -33,7 +33,7 @@ RESUMEF_NS
scheduler_t* _scheduler;
};

inline switch_scheduler_t operator co_await(scheduler_t& sch)
inline switch_scheduler_awaitor operator co_await(scheduler_t& sch)
{
return { &sch };
}

+ 86
- 13
librf/src/type_traits.inl View File

@@ -2,37 +2,110 @@

RESUMEF_NS
{
template<class _Ty>
struct is_coroutine_handle : std::false_type {};
template<class _PromiseT>
struct is_promise : std::false_type {};
struct is_coroutine_handle<std::experimental::coroutine_handle<_PromiseT>> : std::true_type {};
template<class _Ty>
struct is_promise<promise_t<_Ty>> : std::true_type {};
constexpr bool is_coroutine_handle_v = is_coroutine_handle<remove_cvref_t<_Ty>>::value;

template<class _Ty>
constexpr bool is_promise_v = is_promise<remove_cvref_t<_Ty>>::value;
constexpr bool is_valid_await_suspend_return_v = std::is_void_v<_Ty> || std::is_same_v<_Ty, bool> || is_coroutine_handle_v<_Ty>;

template<class _PromiseT>
struct any_type
{
template<class U>
operator U () const
{
return std::declval<U>();
}
};

template<class _Ty, class = std::void_t<>>
struct is_awaitor : std::false_type {};
template<class _Ty>
struct is_awaitor
<_Ty,
std::void_t<
decltype(std::declval<_Ty>().await_ready())
, decltype(std::declval<_Ty>().await_suspend(std::declval<std::experimental::coroutine_handle<promise_t<>>>()))
, decltype(std::declval<_Ty>().await_resume())
>
>
: std::bool_constant<
std::is_constructible_v<bool, decltype(std::declval<_Ty>().await_ready())>
&& is_valid_await_suspend_return_v<
decltype(std::declval<_Ty>().await_suspend(std::declval<std::experimental::coroutine_handle<promise_t<>>>()))
>
>
{};
template<class _Ty>
struct is_awaitor<_Ty&> : is_awaitor<_Ty> {};
template<class _Ty>
struct is_awaitor<_Ty&&> : is_awaitor<_Ty> {};

template<class _Ty>
constexpr bool is_awaitor_v = is_awaitor<remove_cvref_t<_Ty>>::value;

template<class _Ty, class = std::void_t<>>
struct is_future : std::false_type {};
template<class _Ty>
struct is_future<future_t<_Ty>> : std::true_type {};
struct is_future<_Ty,
std::void_t<
decltype(std::declval<_Ty>()._state),
typename _Ty::value_type,
typename _Ty::state_type,
typename _Ty::promise_type
>
> : std::true_type{};
template<class _Ty>
constexpr bool is_future_v = is_future<remove_cvref_t<_Ty>>::value;

template<class _G>
template<class _Ty>
struct is_promise : std::false_type {};
template<class _Ty>
struct is_promise<promise_t<_Ty>> : std::true_type {};
template<class _Ty>
constexpr bool is_promise_v = is_promise<remove_cvref_t<_Ty>>::value;

template<class _Ty>
struct is_generator : std::false_type {};
template <typename _Ty, typename _Alloc>
template <class _Ty, class _Alloc>
struct is_generator<generator_t<_Ty, _Alloc>> : std::true_type {};
template<class _Ty>
constexpr bool is_generator_v = is_generator<remove_cvref_t<_Ty>>::value;

template<class _PromiseT>
template<class _Ty>
struct is_awaitable : std::false_type {};
template<class _Ty>
struct is_awaitable<awaitable_t<_Ty>> : std::true_type {};
template<class _Ty>
constexpr bool is_awaitable_v = is_awaitable<remove_cvref_t<_Ty>>::value;

template<class _Ty>
constexpr bool is_await_suspend_v = is_future_v<_Ty>
|| is_awaitable_v<_Ty>
|| std::is_same_v<remove_cvref_t<_Ty>, switch_scheduler_t>
;

//copy from cppcoro
template<class T>
auto get_awaiter_impl(T&& value, int) noexcept(noexcept(static_cast<T&&>(value).operator co_await()))
-> decltype(static_cast<T&&>(value).operator co_await())
{
return static_cast<T&&>(value).operator co_await();
}
template<class T>
auto get_awaiter_impl(T&& value, long) noexcept(noexcept(operator co_await(static_cast<T&&>(value))))
-> decltype(operator co_await(static_cast<T&&>(value)))
{
return operator co_await(static_cast<T&&>(value));
}
template<class T, std::enable_if_t<is_awaitor_v<T&&>, int> = 0>
T&& get_awaiter_impl(T&& value, std::any) noexcept
{
return static_cast<T&&>(value);
}

template<class T>
auto get_awaiter(T&& value) noexcept(noexcept(detail::get_awaiter_impl(static_cast<T&&>(value), 123)))
-> decltype(detail::get_awaiter_impl(static_cast<T&&>(value), 123))
{
return detail::get_awaiter_impl(static_cast<T&&>(value), 123);
}
}

+ 2
- 413
librf/src/when.h View File

@@ -1,415 +1,4 @@
#pragma once
RESUMEF_NS
{
using any_t = std::any;
using std::any_cast;
}
//纠结过when_any的返回值,是选用index + std::any,还是选用std::variant<>。最终选择了std::any。
//std::variant<>存在第一个元素不能默认构造的问题,需要使用std::monostate来占位,导致下标不是从0开始。
//而且,std::variant<>里面存在类型重复的问题,好几个操作都是病态的
//最最重要的,要统一ranged when_any的返回值,还得做一个运行时通过下标设置std::variant<>的东西
//std::any除了内存布局不太理想,其他方面几乎没缺点(在此应用下)
RESUMEF_NS
{
namespace detail
{
struct when_impl;
typedef _awaker<when_impl> when_awaker;
typedef std::shared_ptr<when_awaker> when_awaker_ptr;
struct when_impl : public std::enable_shared_from_this<when_impl>
{
private:
//typedef spinlock lock_type;
typedef std::recursive_mutex lock_type;
when_awaker_ptr _awakes;
intptr_t _counter;
lock_type _lock;
public:
when_impl(intptr_t initial_counter_);
void signal();
//如果已经触发了awaker,则返回true
bool wait_(const when_awaker_ptr & awaker);
template<class callee_t, class dummy_t = std::enable_if<!std::is_same<std::remove_cv_t<callee_t>, when_awaker_ptr>::value>>
auto wait(callee_t && awaker, dummy_t * dummy_ = nullptr)
{
(void)dummy_;
return wait_(std::make_shared<when_awaker>(std::forward<callee_t>(awaker)));
}
when_impl(const when_impl &) = delete;
when_impl(when_impl &&) = delete;
when_impl & operator = (const when_impl &) = delete;
when_impl & operator = (when_impl &&) = delete;
};
typedef std::shared_ptr<when_impl> when_impl_ptr;
using ignore_type = decltype(std::ignore);
template<class _Ty>
struct remove_future
{
using type = std::remove_reference_t<_Ty>;
using value_type = type;
};
template<>
struct remove_future<void>
{
using type = void;
using value_type = ignore_type;
};
template<class _Ty>
struct remove_future<future_t<_Ty> > : public remove_future<_Ty>
{
};
template<class _Ty>
struct remove_future<future_t<_Ty>&> : public remove_future<_Ty>
{
};
template<class _Ty>
struct remove_future<future_t<_Ty>&&> : public remove_future<_Ty>
{
};
template<class _Ty>
using remove_future_vt = typename remove_future<_Ty>::value_type;
template<class _Fty, class _Ty>
struct when_all_functor
{
using value_type = _Ty;
using future_type = _Fty;
when_impl_ptr _e;
mutable future_type _f;
mutable std::reference_wrapper<value_type> _val;
when_all_functor(const detail::when_impl_ptr & e, future_type f, value_type & v)
: _e(e)
, _f(std::move(f))
, _val(v)
{}
when_all_functor(when_all_functor &&) noexcept = default;
when_all_functor & operator = (const when_all_functor &) = default;
when_all_functor & operator = (when_all_functor &&) = default;
inline future_t<> operator ()() const
{
_val.get() = co_await _f;
_e->signal();
}
};
template<class _Ty>
struct when_all_functor<future_t<>, _Ty>
{
using value_type = _Ty;
using future_type = future_t<>;
when_impl_ptr _e;
mutable future_type _f;
mutable std::reference_wrapper<value_type> _val;
when_all_functor(const detail::when_impl_ptr & e, future_type f, value_type & v)
: _e(e)
, _f(std::move(f))
, _val(v)
{}
when_all_functor(when_all_functor &&) noexcept = default;
when_all_functor & operator = (const when_all_functor &) = default;
when_all_functor & operator = (when_all_functor &&) = default;
inline future_t<> operator ()() const
{
co_await _f;
_val.get() = std::ignore;
_e->signal();
}
};
template<class _Tup, size_t _Idx>
inline void when_all_one__(scheduler_t & , const when_impl_ptr & , _Tup & )
{
}
template<class _Tup, size_t _Idx, class _Fty, class... _Rest>
inline void when_all_one__(scheduler_t& s, const when_impl_ptr & e, _Tup & t, _Fty f, _Rest&&... rest)
{
s + when_all_functor<_Fty, std::tuple_element_t<_Idx, _Tup> >{e, std::move(f), std::get<_Idx>(t)};
when_all_one__<_Tup, _Idx + 1, _Rest...>(s, e, t, std::forward<_Rest>(rest)...);
}
template<class _Val, class _Iter, typename _Fty = decltype(*std::declval<_Iter>())>
inline void when_all_range__(scheduler_t& s, const when_impl_ptr & e, std::vector<_Val> & t, _Iter begin, _Iter end)
{
using future_type = std::remove_reference_t<_Fty>;
const auto _First = begin;
for(; begin != end; ++begin)
s + when_all_functor<future_type, _Val>{e, *begin, t[begin - _First]};
}
template<class _Tup, class... _Fty>
future_t<_Tup> when_all_count(size_t count, const std::shared_ptr<_Tup> & vals, scheduler_t & s, _Fty&&... f)
{
awaitable_t<_Tup> awaitable;
when_impl_ptr _event = std::make_shared<when_impl>(count);
auto awaker = std::make_shared<when_awaker>(
[st = awaitable._state, vals](when_impl * e) -> bool
{
if (e)
st->set_value(*vals);
else
st->throw_exception(channel_exception{ error_code::not_ready });
return true;
});
_event->wait_(awaker);
when_all_one__<_Tup, 0u, _Fty...>(s, _event, *vals, std::forward<_Fty>(f)...);
return awaitable.get_future();
}
template<class _Tup, class _Iter>
future_t<_Tup> when_all_range(size_t count, const std::shared_ptr<_Tup> & vals, scheduler_t& s, _Iter begin, _Iter end)
{
awaitable_t<_Tup> awaitable;
when_impl_ptr _event = std::make_shared<when_impl>(count);
auto awaker = std::make_shared<when_awaker>(
[st = awaitable._state, vals](when_impl * e) -> bool
{
if (e)
st->set_value(*vals);
else
st->throw_exception(channel_exception{ error_code::not_ready });
return true;
});
_event->wait_(awaker);
when_all_range__(s, _event, *vals, begin, end);
return awaitable.get_future();
}
using when_any_pair = std::pair<intptr_t, any_t>;
using when_any_result_ptr = std::shared_ptr<when_any_pair>;
template<class _Fty>
struct when_any_functor
{
using value_type = when_any_pair;
using future_type = _Fty;
when_impl_ptr _e;
mutable future_type _f;
mutable when_any_result_ptr _val;
intptr_t _Idx;
when_any_functor(const when_impl_ptr & e, future_type f, const when_any_result_ptr & v, intptr_t idx)
: _e(e)
, _f(std::move(f))
, _val(v)
, _Idx(idx)
{
assert(idx >= 0);
}
when_any_functor(when_any_functor &&) noexcept = default;
when_any_functor & operator = (const when_any_functor &) = default;
when_any_functor & operator = (when_any_functor &&) = default;
inline future_t<> operator ()() const
{
if (_val->first < 0)
{
auto tval = co_await _f;
if (_val->first < 0)
{
_val->first = _Idx;
_val->second = std::move(tval);
_e->signal();
}
}
else
{
co_await _f;
}
}
};
template<>
struct when_any_functor<future_t<>>
{
using value_type = when_any_pair;
using future_type = future_t<>;
when_impl_ptr _e;
mutable future_type _f;
mutable when_any_result_ptr _val;
intptr_t _Idx;
when_any_functor(const when_impl_ptr & e, future_type f, const when_any_result_ptr & v, intptr_t idx)
: _e(e)
, _f(std::move(f))
, _val(v)
, _Idx(idx)
{
assert(idx >= 0);
}
when_any_functor(when_any_functor &&) noexcept = default;
when_any_functor & operator = (const when_any_functor &) = default;
when_any_functor & operator = (when_any_functor &&) = default;
inline future_t<> operator ()() const
{
if (_val->first < 0)
{
co_await _f;
if (_val->first < 0)
{
_val->first = _Idx;
_e->signal();
}
}
else
{
co_await _f;
}
}
};
template<intptr_t _Idx>
inline void when_any_one__(scheduler_t & , const when_impl_ptr & , const when_any_result_ptr & )
{
}
template<intptr_t _Idx, class _Fty, class... _Rest>
inline void when_any_one__(scheduler_t & s, const when_impl_ptr & e, const when_any_result_ptr & t, _Fty f, _Rest&&... rest)
{
s + when_any_functor<_Fty>{e, std::move(f), t, _Idx};
when_any_one__<_Idx + 1, _Rest...>(s, e, t, std::forward<_Rest>(rest)...);
}
template<class... _Fty>
future_t<when_any_pair> when_any_count(size_t count, const when_any_result_ptr & val_ptr, scheduler_t & s, _Fty&&... f)
{
awaitable_t<when_any_pair> awaitable;
when_impl_ptr _event = std::make_shared<when_impl>(count);
auto awaker = std::make_shared<when_awaker>(
[st = awaitable._state, val_ptr](when_impl * e) -> bool
{
if (e)
st->set_value(*val_ptr);
else
st->throw_exception(channel_exception{ error_code::not_ready });
return true;
});
_event->wait_(awaker);
when_any_one__<0u, _Fty...>(s, _event, val_ptr, std::forward<_Fty>(f)...);
return awaitable.get_future();
}
template<class _Iter, typename _Fty = decltype(*std::declval<_Iter>())>
inline void when_any_range__(scheduler_t & s, const when_impl_ptr & e, const when_any_result_ptr & t, _Iter begin, _Iter end)
{
using future_type = std::remove_reference_t<_Fty>;
const auto _First = begin;
for (; begin != end; ++begin)
s + when_any_functor<future_type>{e, *begin, t, begin - _First};
}
template<class _Iter>
future_t<when_any_pair> when_any_range(size_t count, const when_any_result_ptr & val_ptr, scheduler_t & s, _Iter begin, _Iter end)
{
awaitable_t<when_any_pair> awaitable;
when_impl_ptr _event = std::make_shared<when_impl>(count);
auto awaker = std::make_shared<when_awaker>(
[st = awaitable._state, val_ptr](when_impl * e) -> bool
{
if (e)
st->set_value(*val_ptr);
else
st->throw_exception(channel_exception{ error_code::not_ready });
return true;
});
_event->wait_(awaker);
when_any_range__(s, _event, val_ptr, begin, end);
return awaitable.get_future();
}
}
template<class... _Fty>
auto when_all(scheduler_t & s, _Fty&&... f) -> future_t<std::tuple<detail::remove_future_vt<_Fty>...> >
{
using tuple_type = std::tuple<detail::remove_future_vt<_Fty>...>;
auto vals = std::make_shared<tuple_type>();
return detail::when_all_count(sizeof...(_Fty), vals, s, std::forward<_Fty>(f)...);
}
template<class... _Fty>
auto when_all(_Fty&&... f) -> future_t<std::tuple<detail::remove_future_vt<_Fty>...> >
{
return when_all(*this_scheduler(), std::forward<_Fty>(f)...);
}
template<class _Iter, typename _Fty = decltype(*std::declval<_Iter>())>
auto when_all(scheduler_t & s, _Iter begin, _Iter end) -> future_t<std::vector<detail::remove_future_vt<_Fty> > >
{
using value_type = detail::remove_future_vt<_Fty>;
using vector_type = std::vector<value_type>;
auto vals = std::make_shared<vector_type>(std::distance(begin, end));
return detail::when_all_range(vals->size(), vals, s, begin, end);
}
template<class _Iter, typename _Fty = decltype(*std::declval<_Iter>())>
auto when_all(_Iter begin, _Iter end) -> future_t<std::vector<detail::remove_future_vt<_Fty> > >
{
return when_all(*this_scheduler(), begin, end);
}
template<class... _Fty>
auto when_any(scheduler_t & s, _Fty&&... f) -> future_t<detail::when_any_pair>
{
auto vals = std::make_shared<detail::when_any_pair>(-1, any_t{});
return detail::when_any_count(sizeof...(_Fty) ? 1 : 0, vals, s, std::forward<_Fty>(f)...);
}
template<class... _Fty>
auto when_any(_Fty&&... f) -> future_t<detail::when_any_pair>
{
return when_any(*this_scheduler(), std::forward<_Fty>(f)...);
}
template<class _Iter, typename _Fty = decltype(*std::declval<_Iter>())>
auto when_any(scheduler_t & s, _Iter begin, _Iter end) -> future_t<detail::when_any_pair>
{
auto vals = std::make_shared<detail::when_any_pair>(-1, any_t{});
return detail::when_any_range((begin != end) ? 1 : 0, vals, s, begin, end);
}
template<class _Iter, typename _Fty = decltype(*std::declval<_Iter>())>
auto when_any(_Iter begin, _Iter end) -> future_t<detail::when_any_pair>
{
return when_any(*this_scheduler(), begin, end);
}
}
//#include "when_v1.h"
#include "when_v2.h"

librf/src/when.cpp → librf/src/when_v1.cpp View File

@@ -1,39 +1,39 @@
#include "../librf.h"
RESUMEF_NS
{
namespace detail
{
when_impl::when_impl(intptr_t initial_counter_)
: _counter(initial_counter_)
{
}
void when_impl::signal()
{
scoped_lock<lock_type> lock_(this->_lock);
if (--this->_counter == 0)
{
_awakes->awake(this, 1);
}
}
bool when_impl::wait_(const when_awaker_ptr & awaker)
{
assert(awaker);
scoped_lock<lock_type> lock_(this->_lock);
if (this->_counter == 0)
{
awaker->awake(this, 1);
return true;
}
else
{
this->_awakes = awaker;
return false;
}
}
}
}
#include "../librf.h"
RESUMEF_NS
{
namespace detail
{
when_impl::when_impl(intptr_t initial_counter_)
: _counter(initial_counter_)
{
}
void when_impl::signal()
{
scoped_lock<lock_type> lock_(this->_lock);
if (--this->_counter == 0)
{
_awakes->awake(this, 1);
}
}
bool when_impl::wait_(const when_awaker_ptr & awaker)
{
assert(awaker);
scoped_lock<lock_type> lock_(this->_lock);
if (this->_counter == 0)
{
awaker->awake(this, 1);
return true;
}
else
{
this->_awakes = awaker;
return false;
}
}
}
}

+ 387
- 0
librf/src/when_v1.h View File

@@ -0,0 +1,387 @@
#pragma once

RESUMEF_NS
{
using any_t = std::any;
using std::any_cast;
}

//纠结过when_any的返回值,是选用index + std::any,还是选用std::variant<>。最终选择了std::any。
//std::variant<>存在第一个元素不能默认构造的问题,需要使用std::monostate来占位,导致下标不是从0开始。
//而且,std::variant<>里面存在类型重复的问题,好几个操作都是病态的
//最最重要的,要统一ranged when_any的返回值,还得做一个运行时通过下标设置std::variant<>的东西
//std::any除了内存布局不太理想,其他方面几乎没缺点(在此应用下)

RESUMEF_NS
{
namespace detail
{
struct when_impl;
typedef _awaker<when_impl> when_awaker;
typedef std::shared_ptr<when_awaker> when_awaker_ptr;

struct when_impl : public std::enable_shared_from_this<when_impl>
{
private:
//typedef spinlock lock_type;
typedef std::recursive_mutex lock_type;

when_awaker_ptr _awakes;
intptr_t _counter;
lock_type _lock;
public:
when_impl(intptr_t initial_counter_);

void signal();

//如果已经触发了awaker,则返回true
bool wait_(const when_awaker_ptr & awaker);

template<class callee_t, class dummy_t = std::enable_if<!std::is_same<std::remove_cv_t<callee_t>, when_awaker_ptr>::value>>
auto wait(callee_t && awaker, dummy_t * dummy_ = nullptr)
{
(void)dummy_;
return wait_(std::make_shared<when_awaker>(std::forward<callee_t>(awaker)));
}

when_impl(const when_impl &) = delete;
when_impl(when_impl &&) = delete;
when_impl & operator = (const when_impl &) = delete;
when_impl & operator = (when_impl &&) = delete;
};
typedef std::shared_ptr<when_impl> when_impl_ptr;

template<class _Fty, class _Ty>
struct when_all_functor
{
using value_type = _Ty;
using future_type = _Fty;

when_impl_ptr _e;
mutable future_type _f;
mutable std::reference_wrapper<value_type> _val;

when_all_functor(const detail::when_impl_ptr & e, future_type f, value_type & v)
: _e(e)
, _f(std::move(f))
, _val(v)
{}
when_all_functor(when_all_functor &&) noexcept = default;
when_all_functor & operator = (const when_all_functor &) = default;
when_all_functor & operator = (when_all_functor &&) = default;

inline future_t<> operator ()() const
{
_val.get() = co_await _f;
_e->signal();
}
};

template<class _Ty>
struct when_all_functor<future_t<>, _Ty>
{
using value_type = _Ty;
using future_type = future_t<>;

when_impl_ptr _e;
mutable future_type _f;
mutable std::reference_wrapper<value_type> _val;

when_all_functor(const detail::when_impl_ptr & e, future_type f, value_type & v)
: _e(e)
, _f(std::move(f))
, _val(v)
{}
when_all_functor(when_all_functor &&) noexcept = default;
when_all_functor & operator = (const when_all_functor &) = default;
when_all_functor & operator = (when_all_functor &&) = default;

inline future_t<> operator ()() const
{
co_await _f;
_val.get() = std::ignore;
_e->signal();
}
};

template<class _Tup, size_t _Idx>
inline void when_all_one__(scheduler_t & , const when_impl_ptr & , _Tup & )
{
}

template<class _Tup, size_t _Idx, class _Fty, class... _Rest>
inline void when_all_one__(scheduler_t& s, const when_impl_ptr & e, _Tup & t, _Fty f, _Rest&&... rest)
{
s + when_all_functor<_Fty, std::tuple_element_t<_Idx, _Tup> >{e, std::move(f), std::get<_Idx>(t)};

when_all_one__<_Tup, _Idx + 1, _Rest...>(s, e, t, std::forward<_Rest>(rest)...);
}

template<class _Val, class _Iter, typename _Fty = decltype(*std::declval<_Iter>())>
inline void when_all_range__(scheduler_t& s, const when_impl_ptr & e, std::vector<_Val> & t, _Iter begin, _Iter end)
{
using future_type = std::remove_reference_t<_Fty>;

const auto _First = begin;
for(; begin != end; ++begin)
s + when_all_functor<future_type, _Val>{e, *begin, t[begin - _First]};
}



template<class _Tup, class... _Fty>
future_t<_Tup> when_all_count(size_t count, const std::shared_ptr<_Tup> & vals, scheduler_t & s, _Fty&&... f)
{
awaitable_t<_Tup> awaitable;

when_impl_ptr _event = std::make_shared<when_impl>(count);
auto awaker = std::make_shared<when_awaker>(
[st = awaitable._state, vals](when_impl * e) -> bool
{
if (e)
st->set_value(*vals);
else
st->throw_exception(channel_exception{ error_code::not_ready });
return true;
});
_event->wait_(awaker);

when_all_one__<_Tup, 0u, _Fty...>(s, _event, *vals, std::forward<_Fty>(f)...);

return awaitable.get_future();
}

template<class _Tup, class _Iter>
future_t<_Tup> when_all_range(size_t count, const std::shared_ptr<_Tup> & vals, scheduler_t& s, _Iter begin, _Iter end)
{
awaitable_t<_Tup> awaitable;

when_impl_ptr _event = std::make_shared<when_impl>(count);
auto awaker = std::make_shared<when_awaker>(
[st = awaitable._state, vals](when_impl * e) -> bool
{
if (e)
st->set_value(*vals);
else
st->throw_exception(channel_exception{ error_code::not_ready });
return true;
});
_event->wait_(awaker);

when_all_range__(s, _event, *vals, begin, end);

return awaitable.get_future();
}

template<class _Fty>
struct when_any_functor
{
using value_type = when_any_pair;
using future_type = _Fty;

when_impl_ptr _e;
mutable future_type _f;
mutable when_any_result_ptr _val;
intptr_t _Idx;

when_any_functor(const when_impl_ptr & e, future_type f, const when_any_result_ptr & v, intptr_t idx)
: _e(e)
, _f(std::move(f))
, _val(v)
, _Idx(idx)
{
assert(idx >= 0);
}
when_any_functor(when_any_functor &&) noexcept = default;
when_any_functor & operator = (const when_any_functor &) = default;
when_any_functor & operator = (when_any_functor &&) = default;

inline future_t<> operator ()() const
{
if (_val->first < 0)
{
auto tval = co_await _f;
if (_val->first < 0)
{
_val->first = _Idx;
_val->second = std::move(tval);
_e->signal();
}
}
else
{
co_await _f;
}
}
};

template<>
struct when_any_functor<future_t<>>
{
using value_type = when_any_pair;
using future_type = future_t<>;

when_impl_ptr _e;
mutable future_type _f;
mutable when_any_result_ptr _val;
intptr_t _Idx;

when_any_functor(const when_impl_ptr & e, future_type f, const when_any_result_ptr & v, intptr_t idx)
: _e(e)
, _f(std::move(f))
, _val(v)
, _Idx(idx)
{
assert(idx >= 0);
}
when_any_functor(when_any_functor &&) noexcept = default;
when_any_functor & operator = (const when_any_functor &) = default;
when_any_functor & operator = (when_any_functor &&) = default;

inline future_t<> operator ()() const
{
if (_val->first < 0)
{
co_await _f;
if (_val->first < 0)
{
_val->first = _Idx;
_e->signal();
}
}
else
{
co_await _f;
}
}
};

template<intptr_t _Idx>
inline void when_any_one__(scheduler_t & , const when_impl_ptr & , const when_any_result_ptr & )
{
}

template<intptr_t _Idx, class _Fty, class... _Rest>
inline void when_any_one__(scheduler_t & s, const when_impl_ptr & e, const when_any_result_ptr & t, _Fty f, _Rest&&... rest)
{
s + when_any_functor<_Fty>{e, std::move(f), t, _Idx};

when_any_one__<_Idx + 1, _Rest...>(s, e, t, std::forward<_Rest>(rest)...);
}

template<class... _Fty>
future_t<when_any_pair> when_any_count(size_t count, const when_any_result_ptr & val_ptr, scheduler_t & s, _Fty&&... f)
{
awaitable_t<when_any_pair> awaitable;

when_impl_ptr _event = std::make_shared<when_impl>(count);
auto awaker = std::make_shared<when_awaker>(
[st = awaitable._state, val_ptr](when_impl * e) -> bool
{
if (e)
st->set_value(*val_ptr);
else
st->throw_exception(channel_exception{ error_code::not_ready });
return true;
});
_event->wait_(awaker);

when_any_one__<0u, _Fty...>(s, _event, val_ptr, std::forward<_Fty>(f)...);

return awaitable.get_future();
}

template<class _Iter, typename _Fty = decltype(*std::declval<_Iter>())>
inline void when_any_range__(scheduler_t & s, const when_impl_ptr & e, const when_any_result_ptr & t, _Iter begin, _Iter end)
{
using future_type = std::remove_reference_t<_Fty>;

const auto _First = begin;
for (; begin != end; ++begin)
s + when_any_functor<future_type>{e, *begin, t, begin - _First};
}

template<class _Iter>
future_t<when_any_pair> when_any_range(size_t count, const when_any_result_ptr & val_ptr, scheduler_t & s, _Iter begin, _Iter end)
{
awaitable_t<when_any_pair> awaitable;

when_impl_ptr _event = std::make_shared<when_impl>(count);
auto awaker = std::make_shared<when_awaker>(
[st = awaitable._state, val_ptr](when_impl * e) -> bool
{
if (e)
st->set_value(*val_ptr);
else
st->throw_exception(channel_exception{ error_code::not_ready });
return true;
});
_event->wait_(awaker);

when_any_range__(s, _event, val_ptr, begin, end);

return awaitable.get_future();
}
}

namespace when_v1
{
template<class... _Fty>
auto when_all(scheduler_t& s, _Fty&&... f) -> future_t<std::tuple<detail::remove_future_vt<_Fty>...> >
{
using tuple_type = std::tuple<detail::remove_future_vt<_Fty>...>;
auto vals = std::make_shared<tuple_type>();

return detail::when_all_count(sizeof...(_Fty), vals, s, std::forward<_Fty>(f)...);
}
template<class _Iter, typename _Fty = decltype(*std::declval<_Iter>())>
auto when_all(scheduler_t& s, _Iter begin, _Iter end) -> future_t<std::vector<detail::remove_future_vt<_Fty> > >
{
using value_type = detail::remove_future_vt<_Fty>;
using vector_type = std::vector<value_type>;
auto vals = std::make_shared<vector_type>(std::distance(begin, end));

return detail::when_all_range(vals->size(), vals, s, begin, end);
}
template<class... _Fty>
auto when_all(_Fty&&... f) -> future_t<std::tuple<detail::remove_future_vt<_Fty>...> >
{
co_return co_await when_all(*current_scheduler(), std::forward<_Fty>(f)...);
}
template<class _Iter, typename _Fty = decltype(*std::declval<_Iter>())>
auto when_all(_Iter begin, _Iter end) -> future_t<std::vector<detail::remove_future_vt<_Fty> > >
{
co_return co_await when_all(*current_scheduler(), begin, end);
}




template<class... _Fty>
auto when_any(scheduler_t& s, _Fty&&... f) -> future_t<detail::when_any_pair>
{
auto vals = std::make_shared<detail::when_any_pair>(-1, any_t{});

return detail::when_any_count(sizeof...(_Fty) ? 1 : 0, vals, s, std::forward<_Fty>(f)...);
}
template<class _Iter, typename _Fty = decltype(*std::declval<_Iter>())>
auto when_any(scheduler_t& s, _Iter begin, _Iter end) -> future_t<detail::when_any_pair>
{
auto vals = std::make_shared<detail::when_any_pair>(-1, any_t{});

return detail::when_any_range((begin != end) ? 1 : 0, vals, s, begin, end);
}

template<class... _Fty>
auto when_any(_Fty&&... f) -> future_t<detail::when_any_pair>
{
co_return co_await when_any(*current_scheduler(), std::forward<_Fty>(f)...);
}
template<class _Iter, typename _Fty = decltype(*std::declval<_Iter>())>
auto when_any(_Iter begin, _Iter end) -> future_t<detail::when_any_pair>
{
co_return co_await when_any(*current_scheduler(), begin, end);
}
}
}

+ 58
- 0
librf/src/when_v2.cpp View File

@@ -0,0 +1,58 @@
#include "../librf.h"

RESUMEF_NS
{
namespace detail
{
state_when_t::state_when_t(intptr_t counter_)
:_counter(counter_)
{
}

void state_when_t::resume()
{
coroutine_handle<> handler = _coro;
if (handler)
{
_coro = nullptr;
_scheduler->del_final(this);
handler.resume();
}
}

bool state_when_t::has_handler() const noexcept
{
return (bool)_coro;
}

void state_when_t::on_cancel() noexcept
{
scoped_lock<lock_type> lock_(_lock);

_counter.store(0);
this->_coro = nullptr;
}

bool state_when_t::on_notify_one()
{
scoped_lock<lock_type> lock_(_lock);

if (_counter.fetch_sub(1, std::memory_order_acq_rel) == 1)
{
assert(this->_scheduler != nullptr);
if (this->_coro)
this->_scheduler->add_generator(this);

return true;
}
return false;
}

bool state_when_t::on_timeout()
{
scoped_lock<lock_type> lock_(_lock);

return false;
}
}
}

+ 310
- 0
librf/src/when_v2.h View File

@@ -0,0 +1,310 @@
#pragma once

RESUMEF_NS
{
using any_t = std::any;
using std::any_cast;
}

//纠结过when_any的返回值,是选用index + std::any,还是选用std::variant<>。最终选择了std::any。
//std::variant<>存在第一个元素不能默认构造的问题,需要使用std::monostate来占位,导致下标不是从0开始。
//而且,std::variant<>里面存在类型重复的问题,好几个操作都是病态的
//最最重要的,要统一ranged when_any的返回值,还得做一个运行时通过下标设置std::variant<>的东西
//std::any除了内存布局不太理想,其他方面几乎没缺点(在此应用下)

RESUMEF_NS
{
namespace detail
{
struct state_when_t : public state_base_t
{
state_when_t(intptr_t counter_);

virtual void resume() override;
virtual bool has_handler() const noexcept override;

void on_cancel() noexcept;
bool on_notify_one();
bool on_timeout();

//将自己加入到通知链表里
template<class _PromiseT, typename = std::enable_if_t<is_promise_v<_PromiseT>>>
scheduler_t* on_await_suspend(coroutine_handle<_PromiseT> handler) noexcept
{
_PromiseT& promise = handler.promise();
auto* parent_state = promise.get_state();
scheduler_t* sch = parent_state->get_scheduler();

this->_scheduler = sch;
this->_coro = handler;

return sch;
}

typedef spinlock lock_type;
lock_type _lock;
std::atomic<intptr_t> _counter;
};

template<class _Ty>
struct [[nodiscard]] when_future_t
{
using value_type = _Ty;
using state_type = detail::state_when_t;
using promise_type = promise_t<value_type>;
using future_type = when_future_t<value_type>;
using lock_type = typename state_type::lock_type;

counted_ptr<state_type> _state;
std::shared_ptr<value_type> _values;

when_future_t(intptr_t count_) noexcept
: _state(new state_type(count_))
, _values(std::make_shared<value_type>())
{
}

bool await_ready() noexcept
{
return _state->_counter.load(std::memory_order_relaxed) == 0;
}

template<class _PromiseT, typename = std::enable_if_t<is_promise_v<_PromiseT>>>
void await_suspend(coroutine_handle<_PromiseT> handler)
{
_state->on_await_suspend(handler);
}

value_type await_resume() noexcept(std::is_nothrow_move_constructible_v<value_type>)
{
return std::move(*_values);
}
};


using ignore_type = std::remove_const_t<decltype(std::ignore)>;

template<class _Ty>
struct remove_future
{
using type = std::remove_reference_t<_Ty>;
using value_type = type;
};
template<>
struct remove_future<void>
{
using type = void;
using value_type = ignore_type;
};
template<class _Ty>
struct remove_future<future_t<_Ty> > : public remove_future<_Ty>{};
template<class _Ty>
struct remove_future<future_t<_Ty>&> : public remove_future<_Ty>{};
template<class _Ty>
struct remove_future<future_t<_Ty>&&> : public remove_future<_Ty>{};
template<class _Ty>
using remove_future_t = typename remove_future<_Ty>::value_type;


template<class _Awaitable, class _Ty>
future_t<> when_all_connector(state_when_t* state, _Awaitable awaitor, _Ty& value)
{
static_assert(is_awaitor_v<_Awaitable>);

if constexpr(std::is_same_v<_Ty, ignore_type>)
co_await awaitor;
else
value = co_await awaitor;
state->on_notify_one();
};

template<class _Tup, size_t _Idx>
inline void when_all_one__(scheduler_t& , state_when_t*, _Tup& )
{
}

template<class _Tup, size_t _Idx, class _Awaitable, class... _Rest>
inline void when_all_one__(scheduler_t& sch, state_when_t* state, _Tup& values, _Awaitable&& awaitable, _Rest&&... rest)
{
sch + when_all_connector(state, std::forward<_Awaitable>(awaitable), std::get<_Idx>(values));

when_all_one__<_Tup, _Idx + 1, _Rest...>(sch, state, values, std::forward<_Rest>(rest)...);
}

template<class _Val, class _Iter, typename _Awaitable = decltype(*std::declval<_Iter>())>
inline void when_all_range__(scheduler_t& sch, state_when_t* state, std::vector<_Val> & values, _Iter begin, _Iter end)
{
const auto _First = begin;
intptr_t _Idx = 0;
for (; begin != end; ++begin, ++_Idx)
{
sch + when_all_connector(state, std::move(*begin), values[_Idx]);
}
}

//-----------------------------------------------------------------------------------------------------------------------------------------

using when_any_pair = std::pair<intptr_t, any_t>;
using when_any_pair_ptr = std::shared_ptr<when_any_pair>;

template<class _Awaitable>
future_t<> when_any_connector(counted_ptr<state_when_t> state, _Awaitable awaitor, when_any_pair_ptr value, intptr_t idx)
{
assert(idx >= 0);
static_assert(is_awaitor_v<_Awaitable>);

using value_type = remove_future_t<_Awaitable>;

if constexpr (std::is_same_v<value_type, ignore_type>)
{
co_await awaitor;

intptr_t oldValue = -1;
if (reinterpret_cast<std::atomic<intptr_t>&>(value->first).compare_exchange_strong(oldValue, idx))
{
state->on_notify_one();
}
}
else
{
decltype(auto) result = co_await awaitor;

intptr_t oldValue = -1;
if (reinterpret_cast<std::atomic<intptr_t>&>(value->first).compare_exchange_strong(oldValue, idx))
{
value->second = std::move(result);

state->on_notify_one();
}
}
};

inline void when_any_one__(scheduler_t&, state_when_t*, when_any_pair_ptr, intptr_t)
{
}

template<class _Awaitable, class... _Rest>
inline void when_any_one__(scheduler_t& sch, state_when_t* state, when_any_pair_ptr value, intptr_t _Idx, _Awaitable&& awaitable, _Rest&&... rest)
{
sch + when_any_connector(state, awaitable, value, _Idx);

when_any_one__(sch, state, value, _Idx + 1, std::forward<_Rest>(rest)...);
}

template<class _Iter>
inline void when_any_range__(scheduler_t& sch, state_when_t* state, when_any_pair_ptr value, _Iter begin, _Iter end)
{
const auto _First = begin;
intptr_t _Idx = 0;
for (; begin != end; ++begin, ++_Idx)
{
sch + when_any_connector(state, *begin, value, static_cast<intptr_t>(_Idx));
}
}
}

inline namespace when_v2
{
template<class... _Awaitable,
class = std::enable_if_t<std::conjunction_v<is_awaitor<_Awaitable>...>>
>
auto when_all(scheduler_t& sch, _Awaitable&&... args)
-> detail::when_future_t<std::tuple<detail::remove_future_t<_Awaitable>...> >
{
using tuple_type = std::tuple<detail::remove_future_t<_Awaitable>...>;

detail::when_future_t<tuple_type> awaitor{ sizeof...(_Awaitable) };
detail::when_all_one__<tuple_type, 0u, _Awaitable...>(sch, awaitor._state.get(), *awaitor._values, std::forward<_Awaitable>(args)...);

return awaitor;
}

template<class _Iter,
class _Awaitable = decltype(*std::declval<_Iter>()),
class = std::enable_if_t<is_awaitor_v<_Awaitable>>
>
auto when_all(scheduler_t& sch, _Iter begin, _Iter end)
-> detail::when_future_t<std::vector<detail::remove_future_t<_Awaitable> > >
{
using value_type = detail::remove_future_t<_Awaitable>;
using vector_type = std::vector<value_type>;

detail::when_future_t<vector_type> awaitor{ std::distance(begin, end) };
awaitor._values->resize(end - begin);
when_all_range__(sch, awaitor._state.get(), *awaitor._values, begin, end);

return awaitor;
}

template<class... _Awaitable,
class = std::enable_if_t<std::conjunction_v<is_awaitor<_Awaitable>...>>
>
auto when_all(_Awaitable&&... awaitor)
-> future_t<std::tuple<detail::remove_future_t<_Awaitable>...>>
{
co_return co_await when_all(*current_scheduler(), std::forward<_Awaitable>(awaitor)...);
}

template<class _Iter,
class _Awaitable = decltype(*std::declval<_Iter>()),
class = std::enable_if_t<is_awaitor_v<_Awaitable>>
>
auto when_all(_Iter begin, _Iter end)
-> future_t<std::vector<detail::remove_future_t<_Awaitable>>>
{
co_return co_await when_all(*current_scheduler(), begin, end);
}






template<class... _Awaitable,
class = std::enable_if_t<std::conjunction_v<is_awaitor<_Awaitable>...>>
>
auto when_any(scheduler_t& sch, _Awaitable&&... args)
-> detail::when_future_t<detail::when_any_pair>
{
detail::when_future_t<detail::when_any_pair> awaitor{ sizeof...(_Awaitable) > 0 ? 1 : 0 };
awaitor._values->first = -1;
detail::when_any_one__(sch, awaitor._state.get(), awaitor._values, 0, std::forward<_Awaitable>(args)...);

return awaitor;
}

template<class _Iter,
typename _Awaitable = decltype(*std::declval<_Iter>()),
class = std::enable_if_t<is_awaitor_v<_Awaitable>>
>
auto when_any(scheduler_t& sch, _Iter begin, _Iter end)
-> detail::when_future_t<detail::when_any_pair>
{
detail::when_future_t<detail::when_any_pair> awaitor{ begin == end ? 0 : 1 };
awaitor._values->first = -1;
detail::when_any_range__<_Iter>(sch, awaitor._state.get(), awaitor._values, begin, end);

return awaitor;
}

template<class... _Awaitable,
class = std::enable_if_t<std::conjunction_v<is_awaitor<_Awaitable>...>>
>
auto when_any(_Awaitable&&... awaitor)
-> future_t<detail::when_any_pair>
{
co_return co_await when_any(*current_scheduler(), std::forward<_Awaitable>(awaitor)...);
}

template<class _Iter,
typename _Awaitable = decltype(*std::declval<_Iter>()),
class = std::enable_if_t<is_awaitor_v<_Awaitable>>
>
auto when_any(_Iter begin, _Iter end)
-> future_t<detail::when_any_pair>
{
co_return co_await when_any(*current_scheduler(), begin, end);
}

}
}

+ 1
- 9
tutorial/test_async_when_all.cpp View File

@@ -12,14 +12,6 @@
using namespace resumef;
template<class... _Fty>
auto when_all2(_Fty&&... f) -> future_t<std::tuple<detail::remove_future_vt<_Fty>...>>
{
using tuple_type = std::tuple<detail::remove_future_vt<_Fty>...>;
co_return co_await when_all(*current_scheduler(), std::forward<_Fty>(f)...);
}
void test_when_any()
{
using namespace std::chrono;
@@ -100,7 +92,7 @@ void test_when_all()
co_await when_all();
std::cout << "when all: zero!" << std::endl << std::endl;
auto ab = co_await when_all2(my_sleep("a"), my_sleep_v("b"));
auto ab = co_await when_all(my_sleep("a"), my_sleep_v("b"));
//ab.1 is std::ignore
std::cout << "when all:" << std::get<0>(ab) << std::endl << std::endl;

+ 2
- 2
vs_proj/librf.cpp View File

@@ -43,8 +43,8 @@ int main(int argc, const char* argv[])
//test_ring_queue<resumef::ring_queue_spinlock<int, false, uint32_t>>();
//test_ring_queue<resumef::ring_queue_lockfree<int, uint64_t>>();
resumable_main_switch_scheduler();
//resumable_main_when_all();
//resumable_main_switch_scheduler();
resumable_main_when_all();
//resumable_main_event_v2();
return 0;

+ 4
- 1
vs_proj/librf.vcxproj View File

@@ -178,6 +178,8 @@
<ItemGroup>
<ClCompile Include="..\benchmark\benchmark_asio_echo.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\benchmark\benchmark_async_mem.cpp" />
<ClCompile Include="..\benchmark\benchmark_channel_passing_next.cpp" />
@@ -189,7 +191,7 @@
<ClCompile Include="..\librf\src\sleep.cpp" />
<ClCompile Include="..\librf\src\state.cpp" />
<ClCompile Include="..\librf\src\timer.cpp" />
<ClCompile Include="..\librf\src\when.cpp" />
<ClCompile Include="..\librf\src\when_v2.cpp" />
<ClCompile Include="..\tutorial\test_async_cb.cpp" />
<ClCompile Include="..\tutorial\test_async_channel.cpp" />
<ClCompile Include="..\tutorial\test_async_channel_mult_thread.cpp" />
@@ -249,6 +251,7 @@
<ClInclude Include="..\librf\src\unix\coroutine.h" />
<ClInclude Include="..\librf\src\utils.h" />
<ClInclude Include="..\librf\src\when.h" />
<ClInclude Include="..\librf\src\when_v2.h" />
<ClInclude Include="..\librf\src\_awaker.h" />
<ClInclude Include="..\tutorial\test_ring_queue.h" />
<ClInclude Include="dcas.h" />

+ 6
- 3
vs_proj/librf.vcxproj.filters View File

@@ -94,9 +94,6 @@
<ClCompile Include="..\tutorial\test_async_when_all.cpp">
<Filter>tutorial</Filter>
</ClCompile>
<ClCompile Include="..\librf\src\when.cpp">
<Filter>librf\src</Filter>
</ClCompile>
<ClCompile Include="..\benchmark\benchmark_asio_echo.cpp">
<Filter>benchmark</Filter>
</ClCompile>
@@ -121,6 +118,9 @@
<ClCompile Include="..\tutorial\test_async_event_v2.cpp">
<Filter>tutorial</Filter>
</ClCompile>
<ClCompile Include="..\librf\src\when_v2.cpp">
<Filter>librf\src</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\librf\librf.h">
@@ -228,6 +228,9 @@
<ClInclude Include="..\librf\src\current_scheduler.h">
<Filter>librf\src</Filter>
</ClInclude>
<ClInclude Include="..\librf\src\when_v2.h">
<Filter>librf\src</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="..\librf\src\asio_task_1.12.0.inl">

Loading…
Cancel
Save