mirror of
https://github.com/tearshark/librf.git
synced 2024-10-04 08:50:31 +08:00
全面兼容clang编译器,并通过大部分测试范例
This commit is contained in:
parent
3ba9a56cae
commit
0739e99ab2
@ -31,7 +31,11 @@
|
|||||||
#include <thread>
|
#include <thread>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#if defined(__clang__) && _WIN32
|
||||||
|
#include "src/unix/coroutine.h" //编译器内建的协程函数,MSVC和clang不一样
|
||||||
|
#else
|
||||||
#include <experimental/coroutine>
|
#include <experimental/coroutine>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "src/def.h"
|
#include "src/def.h"
|
||||||
#include "src/spinlock.h"
|
#include "src/spinlock.h"
|
||||||
@ -40,7 +44,6 @@
|
|||||||
#include "src/future.h"
|
#include "src/future.h"
|
||||||
#include "src/promise.h"
|
#include "src/promise.h"
|
||||||
#include "src/awaitable.h"
|
#include "src/awaitable.h"
|
||||||
#include "src/switch_scheduler.h"
|
|
||||||
|
|
||||||
#include "src/rf_task.h"
|
#include "src/rf_task.h"
|
||||||
#include "src/utils.h"
|
#include "src/utils.h"
|
||||||
@ -50,6 +53,7 @@
|
|||||||
#include "src/promise.inl"
|
#include "src/promise.inl"
|
||||||
#include "src/state.inl"
|
#include "src/state.inl"
|
||||||
|
|
||||||
|
#include "src/switch_scheduler.h"
|
||||||
#include "src/_awaker.h"
|
#include "src/_awaker.h"
|
||||||
#include "src/event.h"
|
#include "src/event.h"
|
||||||
#include "src/mutex.h"
|
#include "src/mutex.h"
|
||||||
|
@ -35,18 +35,7 @@ RESUMEF_NS
|
|||||||
return future_type{ this->_state };
|
return future_type{ this->_state };
|
||||||
}
|
}
|
||||||
|
|
||||||
mutable counted_ptr<state_type> _state = _Alloc_state();
|
mutable counted_ptr<state_type> _state = state_future_t::_Alloc_state<state_type>(true);
|
||||||
private:
|
|
||||||
static state_type* _Alloc_state()
|
|
||||||
{
|
|
||||||
_Alloc_char _Al;
|
|
||||||
size_t _Size = sizeof(state_type);
|
|
||||||
#if RESUMEF_DEBUG_COUNTER
|
|
||||||
std::cout << "awaitable_t::alloc, size=" << _Size << std::endl;
|
|
||||||
#endif
|
|
||||||
char * _Ptr = _Al.allocate(_Size);
|
|
||||||
return new(_Ptr) state_type(true);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template<class _Ty>
|
template<class _Ty>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define LIB_RESUMEF_VERSION 20201 // 2.2.1
|
#define LIB_RESUMEF_VERSION 20300 // 2.3.0
|
||||||
|
|
||||||
#if defined(RESUMEF_MODULE_EXPORT)
|
#if defined(RESUMEF_MODULE_EXPORT)
|
||||||
#define RESUMEF_NS export namespace resumef
|
#define RESUMEF_NS export namespace resumef
|
||||||
@ -8,12 +8,20 @@
|
|||||||
#define RESUMEF_NS namespace resumef
|
#define RESUMEF_NS namespace resumef
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
//如果不清楚context frame的内存布局的情况下,该值设置为0
|
||||||
|
#if defined(__clang__) || defined(_MSC_VER)
|
||||||
|
#define RESUMEF_INLINE_STATE 1
|
||||||
|
#else
|
||||||
|
#define RESUMEF_INLINE_STATE 0
|
||||||
|
#endif
|
||||||
|
|
||||||
RESUMEF_NS
|
RESUMEF_NS
|
||||||
{
|
{
|
||||||
struct scheduler_t;
|
struct scheduler_t;
|
||||||
|
|
||||||
template<class _Ty = void>
|
template<class _Ty = void>
|
||||||
struct future_t;
|
struct future_t;
|
||||||
|
|
||||||
using future_vt [[deprecated]] = future_t<>;
|
using future_vt [[deprecated]] = future_t<>;
|
||||||
|
|
||||||
template <typename _Ty = std::nullptr_t, typename _Alloc = std::allocator<char>>
|
template <typename _Ty = std::nullptr_t, typename _Alloc = std::allocator<char>>
|
||||||
@ -33,6 +41,8 @@ RESUMEF_NS
|
|||||||
|
|
||||||
struct state_base_t;
|
struct state_base_t;
|
||||||
|
|
||||||
|
struct switch_scheduler_t;
|
||||||
|
|
||||||
template<class... _Mutexes>
|
template<class... _Mutexes>
|
||||||
using scoped_lock = std::scoped_lock<_Mutexes...>;
|
using scoped_lock = std::scoped_lock<_Mutexes...>;
|
||||||
|
|
||||||
|
@ -109,9 +109,7 @@ RESUMEF_NS
|
|||||||
|
|
||||||
promise_type()
|
promise_type()
|
||||||
{
|
{
|
||||||
state_type* st = get_state();
|
get_state()->set_initial_suspend(coroutine_handle<promise_type>::from_promise(*this));
|
||||||
new(st) state_type(coroutine_handle<promise_type>::from_promise(*this));
|
|
||||||
st->lock();
|
|
||||||
}
|
}
|
||||||
promise_type(promise_type&& _Right) noexcept = default;
|
promise_type(promise_type&& _Right) noexcept = default;
|
||||||
promise_type& operator = (promise_type&& _Right) noexcept = default;
|
promise_type& operator = (promise_type&& _Right) noexcept = default;
|
||||||
@ -123,19 +121,20 @@ RESUMEF_NS
|
|||||||
return generator_t{ *this };
|
return generator_t{ *this };
|
||||||
}
|
}
|
||||||
|
|
||||||
bool initial_suspend()
|
std::experimental::suspend_always initial_suspend()
|
||||||
{
|
{
|
||||||
return true;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool final_suspend()
|
std::experimental::suspend_always final_suspend()
|
||||||
{
|
{
|
||||||
return true;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void yield_value(_Ty const& _Value)
|
std::experimental::suspend_always yield_value(_Ty const& _Value)
|
||||||
{
|
{
|
||||||
_CurrentValue = std::addressof(_Value);
|
_CurrentValue = std::addressof(_Value);
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
//template<class = std::enable_if_t<!std::is_same_v<_Ty, void>, _Ty>>
|
//template<class = std::enable_if_t<!std::is_same_v<_Ty, void>, _Ty>>
|
||||||
@ -170,9 +169,21 @@ RESUMEF_NS
|
|||||||
|
|
||||||
state_type* get_state()
|
state_type* get_state()
|
||||||
{
|
{
|
||||||
|
#if RESUMEF_INLINE_STATE
|
||||||
size_t _State_size = _Align_size<state_type>();
|
size_t _State_size = _Align_size<state_type>();
|
||||||
|
#if defined(__clang__)
|
||||||
|
auto h = coroutine_handle<promise_type>::from_promise(*this);
|
||||||
|
char* ptr = reinterpret_cast<char*>(h.address()) - _State_size;
|
||||||
|
return reinterpret_cast<state_type*>(ptr);
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
char* ptr = reinterpret_cast<char*>(this) - _State_size;
|
char* ptr = reinterpret_cast<char*>(this) - _State_size;
|
||||||
return reinterpret_cast<state_type*>(ptr);
|
return reinterpret_cast<state_type*>(ptr);
|
||||||
|
#else
|
||||||
|
#error "Unknown compiler"
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
return _state.get();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
using _Alloc_char = typename std::allocator_traits<_Alloc>::template rebind_alloc<char>;
|
using _Alloc_char = typename std::allocator_traits<_Alloc>::template rebind_alloc<char>;
|
||||||
@ -183,27 +194,41 @@ RESUMEF_NS
|
|||||||
|
|
||||||
void* operator new(size_t _Size)
|
void* operator new(size_t _Size)
|
||||||
{
|
{
|
||||||
|
_Alloc_char _Al;
|
||||||
|
#if RESUMEF_INLINE_STATE
|
||||||
size_t _State_size = _Align_size<state_type>();
|
size_t _State_size = _Align_size<state_type>();
|
||||||
assert(_Size >= sizeof(uint32_t) && _Size < (std::numeric_limits<uint32_t>::max)() - sizeof(_State_size));
|
assert(_Size >= sizeof(uint32_t) && _Size < (std::numeric_limits<uint32_t>::max)() - sizeof(_State_size));
|
||||||
#if RESUMEF_DEBUG_COUNTER
|
|
||||||
std::cout << "generator_promise::new, size=" << (_Size + _State_size) << std::endl;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
_Alloc_char _Al;
|
|
||||||
char* ptr = _Al.allocate(_Size + _State_size);
|
char* ptr = _Al.allocate(_Size + _State_size);
|
||||||
|
char* _Rptr = ptr + _State_size;
|
||||||
|
#if RESUMEF_DEBUG_COUNTER
|
||||||
|
std::cout << " generator_promise::new, alloc size=" << (_Size + _State_size) << std::endl;
|
||||||
|
std::cout << " generator_promise::new, alloc ptr=" << (void*)ptr << std::endl;
|
||||||
|
std::cout << " generator_promise::new, return ptr=" << (void*)_Rptr << std::endl;
|
||||||
|
#endif
|
||||||
|
|
||||||
//ÔÚ³õʼµØÖ·ÉϹ¹Ôìstate
|
//ÔÚ³õʼµØÖ·ÉϹ¹Ôìstate
|
||||||
{
|
{
|
||||||
state_type* st = new(ptr) state_type(coroutine_handle<promise_type>::from_promise(*(promise_type *)ptr));
|
state_type* st = new(ptr) state_type();
|
||||||
st->lock();
|
st->lock();
|
||||||
*reinterpret_cast<uint32_t*>(ptr + _State_size) = static_cast<uint32_t>(_Size + _State_size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ptr + _State_size;
|
return _Rptr;
|
||||||
|
#else
|
||||||
|
char* ptr = _Al.allocate(_Size);
|
||||||
|
#if RESUMEF_DEBUG_COUNTER
|
||||||
|
std::cout << " generator_promise::new, alloc size=" << _Size << std::endl;
|
||||||
|
std::cout << " generator_promise::new, alloc ptr=" << (void*)ptr << std::endl;
|
||||||
|
std::cout << " generator_promise::new, return ptr=" << (void*)ptr << std::endl;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ptr;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator delete(void* _Ptr, size_t _Size)
|
void operator delete(void* _Ptr, size_t _Size)
|
||||||
{
|
{
|
||||||
|
#if RESUMEF_INLINE_STATE
|
||||||
size_t _State_size = _Align_size<state_type>();
|
size_t _State_size = _Align_size<state_type>();
|
||||||
assert(_Size >= sizeof(uint32_t) && _Size < (std::numeric_limits<uint32_t>::max)() - sizeof(_State_size));
|
assert(_Size >= sizeof(uint32_t) && _Size < (std::numeric_limits<uint32_t>::max)() - sizeof(_State_size));
|
||||||
|
|
||||||
@ -211,7 +236,15 @@ RESUMEF_NS
|
|||||||
|
|
||||||
state_type* st = reinterpret_cast<state_type*>(static_cast<char*>(_Ptr) - _State_size);
|
state_type* st = reinterpret_cast<state_type*>(static_cast<char*>(_Ptr) - _State_size);
|
||||||
st->unlock();
|
st->unlock();
|
||||||
|
#else
|
||||||
|
_Alloc_char _Al;
|
||||||
|
return _Al.deallocate(reinterpret_cast<char *>(_Ptr), _Size);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
#if !RESUMEF_INLINE_STATE
|
||||||
|
private:
|
||||||
|
counted_ptr<state_type> _state = state_generator_t::_Alloc_state();
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef generator_iterator<_Ty, promise_type> iterator;
|
typedef generator_iterator<_Ty, promise_type> iterator;
|
||||||
|
@ -22,13 +22,7 @@ RESUMEF_NS
|
|||||||
promise_impl_t(const promise_impl_t&) = delete;
|
promise_impl_t(const promise_impl_t&) = delete;
|
||||||
promise_impl_t& operator = (const promise_impl_t&) = delete;
|
promise_impl_t& operator = (const promise_impl_t&) = delete;
|
||||||
|
|
||||||
state_type* get_state()
|
auto get_state()->state_type*;
|
||||||
{
|
|
||||||
size_t _State_size = _Align_size<state_type>();
|
|
||||||
char* ptr = reinterpret_cast<char*>(this) - _State_size;
|
|
||||||
return reinterpret_cast<state_type*>(ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend_on_initial initial_suspend() noexcept;
|
suspend_on_initial initial_suspend() noexcept;
|
||||||
suspend_on_final final_suspend() noexcept;
|
suspend_on_final final_suspend() noexcept;
|
||||||
void set_exception(std::exception_ptr e);
|
void set_exception(std::exception_ptr e);
|
||||||
@ -39,42 +33,12 @@ RESUMEF_NS
|
|||||||
void cancellation_requested();
|
void cancellation_requested();
|
||||||
|
|
||||||
using _Alloc_char = std::allocator<char>;
|
using _Alloc_char = std::allocator<char>;
|
||||||
void* operator new(size_t _Size)
|
void* operator new(size_t _Size);
|
||||||
{
|
void operator delete(void* _Ptr, size_t _Size);
|
||||||
size_t _State_size = _Align_size<state_type>();
|
#if !RESUMEF_INLINE_STATE
|
||||||
assert(_Size >= sizeof(uint32_t) && _Size < (std::numeric_limits<uint32_t>::max)() - sizeof(_State_size));
|
private:
|
||||||
|
counted_ptr<state_type> _state = state_future_t::_Alloc_state<state_type>(false);
|
||||||
_Alloc_char _Al;
|
|
||||||
/*If allocation fails, the coroutine throws std::bad_alloc,
|
|
||||||
unless the Promise type defines the member function Promise::get_return_object_on_allocation_failure().
|
|
||||||
If that member function is defined, allocation uses the nothrow form of operator new and on allocation failure,
|
|
||||||
the coroutine immediately returns the object obtained from Promise::get_return_object_on_allocation_failure() to the caller.
|
|
||||||
*/
|
|
||||||
char* ptr = _Al.allocate(_Size + _State_size);
|
|
||||||
#if RESUMEF_DEBUG_COUNTER
|
|
||||||
std::cout << " future_promise::new, alloc size=" << (_Size + _State_size) << std::endl;
|
|
||||||
std::cout << " future_promise::new, alloc ptr=" << (void*)ptr << std::endl;
|
|
||||||
std::cout << " future_promise::new, return ptr=" << (void*)(ptr + _State_size) << std::endl;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//在初始地址上构造state
|
|
||||||
{
|
|
||||||
state_type* st = new(ptr) state_type(_Size + _State_size);
|
|
||||||
st->lock();
|
|
||||||
}
|
|
||||||
|
|
||||||
return ptr + _State_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
void operator delete(void* _Ptr, size_t _Size)
|
|
||||||
{
|
|
||||||
(void)_Size;
|
|
||||||
size_t _State_size = _Align_size<state_type>();
|
|
||||||
assert(_Size >= sizeof(uint32_t) && _Size < (std::numeric_limits<uint32_t>::max)() - sizeof(_State_size));
|
|
||||||
|
|
||||||
state_type* st = reinterpret_cast<state_type*>(static_cast<char*>(_Ptr) - _State_size);
|
|
||||||
st->unlock();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template<class _Ty>
|
template<class _Ty>
|
||||||
@ -86,7 +50,7 @@ RESUMEF_NS
|
|||||||
template<class U>
|
template<class U>
|
||||||
void return_value(U&& val); //co_return val
|
void return_value(U&& val); //co_return val
|
||||||
template<class U>
|
template<class U>
|
||||||
void yield_value(U&& val);
|
std::experimental::suspend_always yield_value(U&& val);
|
||||||
};
|
};
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
@ -95,7 +59,7 @@ RESUMEF_NS
|
|||||||
using promise_impl_t<void>::get_return_object;
|
using promise_impl_t<void>::get_return_object;
|
||||||
|
|
||||||
void return_void(); //co_return;
|
void return_void(); //co_return;
|
||||||
void yield_value();
|
std::experimental::suspend_always yield_value();
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ RESUMEF_NS
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct suspend_on_final
|
struct suspend_on_final
|
||||||
{
|
{
|
||||||
inline bool await_ready() noexcept
|
inline bool await_ready() noexcept
|
||||||
@ -80,6 +81,80 @@ RESUMEF_NS
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename _Ty>
|
||||||
|
auto promise_impl_t<_Ty>::get_state() -> state_type*
|
||||||
|
{
|
||||||
|
#if RESUMEF_INLINE_STATE
|
||||||
|
size_t _State_size = _Align_size<state_type>();
|
||||||
|
#if defined(__clang__)
|
||||||
|
auto h = coroutine_handle<promise_type>::from_promise(*reinterpret_cast<promise_type *>(this));
|
||||||
|
char* ptr = reinterpret_cast<char*>(h.address()) - _State_size;
|
||||||
|
return reinterpret_cast<state_type*>(ptr);
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
char* ptr = reinterpret_cast<char*>(this) - _State_size;
|
||||||
|
return reinterpret_cast<state_type*>(ptr);
|
||||||
|
#else
|
||||||
|
#error "Unknown compiler"
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
return _state.get();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename _Ty>
|
||||||
|
void* promise_impl_t<_Ty>::operator new(size_t _Size)
|
||||||
|
{
|
||||||
|
_Alloc_char _Al;
|
||||||
|
#if RESUMEF_INLINE_STATE
|
||||||
|
size_t _State_size = _Align_size<state_type>();
|
||||||
|
assert(_Size >= sizeof(uint32_t) && _Size < (std::numeric_limits<uint32_t>::max)() - sizeof(_State_size));
|
||||||
|
|
||||||
|
/*If allocation fails, the coroutine throws std::bad_alloc,
|
||||||
|
unless the Promise type defines the member function Promise::get_return_object_on_allocation_failure().
|
||||||
|
If that member function is defined, allocation uses the nothrow form of operator new and on allocation failure,
|
||||||
|
the coroutine immediately returns the object obtained from Promise::get_return_object_on_allocation_failure() to the caller.
|
||||||
|
*/
|
||||||
|
char* ptr = _Al.allocate(_Size + _State_size);
|
||||||
|
char* _Rptr = ptr + _State_size;
|
||||||
|
#if RESUMEF_DEBUG_COUNTER
|
||||||
|
std::cout << " future_promise::new, alloc size=" << (_Size + _State_size) << std::endl;
|
||||||
|
std::cout << " future_promise::new, alloc ptr=" << (void*)ptr << std::endl;
|
||||||
|
std::cout << " future_promise::new, return ptr=" << (void*)_Rptr << std::endl;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//在初始地址上构造state
|
||||||
|
{
|
||||||
|
state_type* st = new(ptr) state_type(_Size + _State_size);
|
||||||
|
st->lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
return _Rptr;
|
||||||
|
#else
|
||||||
|
char* ptr = _Al.allocate(_Size);
|
||||||
|
#if RESUMEF_DEBUG_COUNTER
|
||||||
|
std::cout << " future_promise::new, alloc size=" << (_Size) << std::endl;
|
||||||
|
std::cout << " future_promise::new, alloc ptr=" << (void*)ptr << std::endl;
|
||||||
|
std::cout << " future_promise::new, return ptr=" << (void*)ptr << std::endl;
|
||||||
|
#endif
|
||||||
|
return ptr;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename _Ty>
|
||||||
|
void promise_impl_t<_Ty>::operator delete(void* _Ptr, size_t _Size)
|
||||||
|
{
|
||||||
|
#if RESUMEF_INLINE_STATE
|
||||||
|
(void)_Size;
|
||||||
|
size_t _State_size = _Align_size<state_type>();
|
||||||
|
assert(_Size >= sizeof(uint32_t) && _Size < (std::numeric_limits<uint32_t>::max)() - sizeof(_State_size));
|
||||||
|
|
||||||
|
state_type* st = reinterpret_cast<state_type*>(static_cast<char*>(_Ptr) - _State_size);
|
||||||
|
st->unlock();
|
||||||
|
#else
|
||||||
|
_Alloc_char _Al;
|
||||||
|
return _Al.deallocate(reinterpret_cast<char*>(_Ptr), _Size);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
template<class _Ty>
|
template<class _Ty>
|
||||||
template<class U>
|
template<class U>
|
||||||
@ -90,9 +165,10 @@ RESUMEF_NS
|
|||||||
|
|
||||||
template<class _Ty>
|
template<class _Ty>
|
||||||
template<class U>
|
template<class U>
|
||||||
inline void promise_t<_Ty>::yield_value(U&& val)
|
inline std::experimental::suspend_always promise_t<_Ty>::yield_value(U&& val)
|
||||||
{
|
{
|
||||||
this->get_state()->promise_yield_value(this, std::forward<U>(val));
|
this->get_state()->promise_yield_value(this, std::forward<U>(val));
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void promise_t<void>::return_void()
|
inline void promise_t<void>::return_void()
|
||||||
@ -100,10 +176,10 @@ RESUMEF_NS
|
|||||||
this->get_state()->set_value();
|
this->get_state()->set_value();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void promise_t<void>::yield_value()
|
inline std::experimental::suspend_always promise_t<void>::yield_value()
|
||||||
{
|
{
|
||||||
this->get_state()->promise_yield_value(this);
|
this->get_state()->promise_yield_value(this);
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,12 +58,6 @@ RESUMEF_NS
|
|||||||
std::unique_ptr<task_base_t> del_switch(state_base_t* sptr);
|
std::unique_ptr<task_base_t> del_switch(state_base_t* sptr);
|
||||||
void add_switch(std::unique_ptr<task_base_t> task);
|
void add_switch(std::unique_ptr<task_base_t> task);
|
||||||
|
|
||||||
switch_scheduler_t operator co_await()
|
|
||||||
{
|
|
||||||
return { this };
|
|
||||||
}
|
|
||||||
|
|
||||||
friend struct task_base;
|
|
||||||
friend struct local_scheduler;
|
friend struct local_scheduler;
|
||||||
protected:
|
protected:
|
||||||
scheduler_t();
|
scheduler_t();
|
||||||
|
@ -21,8 +21,10 @@ RESUMEF_NS
|
|||||||
void state_generator_t::destroy_deallocate()
|
void state_generator_t::destroy_deallocate()
|
||||||
{
|
{
|
||||||
size_t _Size = _Align_size<state_generator_t>();
|
size_t _Size = _Align_size<state_generator_t>();
|
||||||
|
#if RESUMEF_INLINE_STATE
|
||||||
char* _Ptr = reinterpret_cast<char*>(this) + _Size;
|
char* _Ptr = reinterpret_cast<char*>(this) + _Size;
|
||||||
_Size = *reinterpret_cast<uint32_t*>(_Ptr);
|
_Size = *reinterpret_cast<uint32_t*>(_Ptr);
|
||||||
|
#endif
|
||||||
#if RESUMEF_DEBUG_COUNTER
|
#if RESUMEF_DEBUG_COUNTER
|
||||||
std::cout << "destroy_deallocate, size=" << _Size << std::endl;
|
std::cout << "destroy_deallocate, size=" << _Size << std::endl;
|
||||||
#endif
|
#endif
|
||||||
@ -34,7 +36,7 @@ RESUMEF_NS
|
|||||||
|
|
||||||
void state_generator_t::resume()
|
void state_generator_t::resume()
|
||||||
{
|
{
|
||||||
if (_coro != nullptr)
|
if (_coro)
|
||||||
{
|
{
|
||||||
_coro.resume();
|
_coro.resume();
|
||||||
if (_coro.done())
|
if (_coro.done())
|
||||||
@ -54,12 +56,12 @@ RESUMEF_NS
|
|||||||
|
|
||||||
bool state_generator_t::is_ready() const
|
bool state_generator_t::is_ready() const
|
||||||
{
|
{
|
||||||
return _coro != nullptr && !_coro.done();
|
return (bool)_coro && !_coro.done();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool state_generator_t::has_handler() const
|
bool state_generator_t::has_handler() const
|
||||||
{
|
{
|
||||||
return _coro != nullptr;
|
return (bool)_coro;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool state_generator_t::switch_scheduler_await_suspend(scheduler_t* sch, coroutine_handle<>)
|
bool state_generator_t::switch_scheduler_await_suspend(scheduler_t* sch, coroutine_handle<>)
|
||||||
@ -90,7 +92,7 @@ RESUMEF_NS
|
|||||||
|
|
||||||
if (_is_initor == initor_type::Initial)
|
if (_is_initor == initor_type::Initial)
|
||||||
{
|
{
|
||||||
assert(_initor != nullptr);
|
assert((bool)_initor);
|
||||||
|
|
||||||
_is_initor = initor_type::None;
|
_is_initor = initor_type::None;
|
||||||
__guard.unlock();
|
__guard.unlock();
|
||||||
@ -99,7 +101,7 @@ RESUMEF_NS
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_coro != nullptr)
|
if (_coro)
|
||||||
{
|
{
|
||||||
coroutine_handle<> handler = _coro;
|
coroutine_handle<> handler = _coro;
|
||||||
_coro = nullptr;
|
_coro = nullptr;
|
||||||
@ -111,6 +113,8 @@ RESUMEF_NS
|
|||||||
|
|
||||||
if (_is_initor == initor_type::Final)
|
if (_is_initor == initor_type::Final)
|
||||||
{
|
{
|
||||||
|
assert((bool)_initor);
|
||||||
|
|
||||||
_is_initor = initor_type::None;
|
_is_initor = initor_type::None;
|
||||||
__guard.unlock();
|
__guard.unlock();
|
||||||
|
|
||||||
@ -122,7 +126,7 @@ RESUMEF_NS
|
|||||||
bool state_future_t::has_handler() const
|
bool state_future_t::has_handler() const
|
||||||
{
|
{
|
||||||
scoped_lock<lock_type> __guard(_mtx);
|
scoped_lock<lock_type> __guard(_mtx);
|
||||||
return _coro != nullptr || _is_initor != initor_type::None;
|
return (bool)_coro || _is_initor != initor_type::None;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool state_future_t::is_ready() const
|
bool state_future_t::is_ready() const
|
||||||
@ -162,7 +166,7 @@ RESUMEF_NS
|
|||||||
if (_parent != nullptr)
|
if (_parent != nullptr)
|
||||||
_parent->switch_scheduler_await_suspend(sch, nullptr);
|
_parent->switch_scheduler_await_suspend(sch, nullptr);
|
||||||
|
|
||||||
if (handler != nullptr)
|
if (handler)
|
||||||
{
|
{
|
||||||
_coro = handler;
|
_coro = handler;
|
||||||
sch->add_generator(this);
|
sch->add_generator(this);
|
||||||
|
@ -48,10 +48,6 @@ RESUMEF_NS
|
|||||||
|
|
||||||
struct state_generator_t : public state_base_t
|
struct state_generator_t : public state_base_t
|
||||||
{
|
{
|
||||||
state_generator_t(coroutine_handle<> handler)
|
|
||||||
{
|
|
||||||
_coro = handler;
|
|
||||||
}
|
|
||||||
private:
|
private:
|
||||||
virtual void destroy_deallocate() override;
|
virtual void destroy_deallocate() override;
|
||||||
public:
|
public:
|
||||||
@ -60,12 +56,20 @@ RESUMEF_NS
|
|||||||
virtual bool is_ready() const override;
|
virtual bool is_ready() const override;
|
||||||
virtual bool switch_scheduler_await_suspend(scheduler_t* sch, coroutine_handle<> handler) override;
|
virtual bool switch_scheduler_await_suspend(scheduler_t* sch, coroutine_handle<> handler) override;
|
||||||
|
|
||||||
static state_generator_t * _Alloc_state(coroutine_handle<> handler)
|
void set_initial_suspend(coroutine_handle<> handler)
|
||||||
{
|
{
|
||||||
|
_coro = handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
static state_generator_t * _Alloc_state()
|
||||||
|
{
|
||||||
|
_Alloc_char _Al;
|
||||||
|
size_t _Size = sizeof(state_generator_t);
|
||||||
#if RESUMEF_DEBUG_COUNTER
|
#if RESUMEF_DEBUG_COUNTER
|
||||||
std::cout << "state_generator_t::alloc, size=" << sizeof(state_generator_t) << std::endl;
|
std::cout << "state_generator_t::alloc, size=" << sizeof(state_generator_t) << std::endl;
|
||||||
#endif
|
#endif
|
||||||
return new state_generator_t(handler);
|
char* _Ptr = _Al.allocate(_Size);
|
||||||
|
return new(_Ptr) state_generator_t();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -146,11 +150,25 @@ RESUMEF_NS
|
|||||||
void promise_initial_suspend(coroutine_handle<_PromiseT> handler);
|
void promise_initial_suspend(coroutine_handle<_PromiseT> handler);
|
||||||
template<class _PromiseT, typename = std::enable_if_t<is_promise_v<_PromiseT>>>
|
template<class _PromiseT, typename = std::enable_if_t<is_promise_v<_PromiseT>>>
|
||||||
void promise_final_suspend(coroutine_handle<_PromiseT> handler);
|
void promise_final_suspend(coroutine_handle<_PromiseT> handler);
|
||||||
|
|
||||||
|
template<class _Sty>
|
||||||
|
static _Sty* _Alloc_state(bool awaitor)
|
||||||
|
{
|
||||||
|
_Alloc_char _Al;
|
||||||
|
size_t _Size = sizeof(_Sty);
|
||||||
|
#if RESUMEF_DEBUG_COUNTER
|
||||||
|
std::cout << "state_future_t::alloc, size=" << _Size << std::endl;
|
||||||
|
#endif
|
||||||
|
char* _Ptr = _Al.allocate(_Size);
|
||||||
|
return new(_Ptr) _Sty(awaitor);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename _Ty>
|
template <typename _Ty>
|
||||||
struct state_t final : public state_future_t
|
struct state_t final : public state_future_t
|
||||||
{
|
{
|
||||||
|
friend state_future_t;
|
||||||
|
|
||||||
using state_future_t::lock_type;
|
using state_future_t::lock_type;
|
||||||
using value_type = _Ty;
|
using value_type = _Ty;
|
||||||
|
|
||||||
@ -162,7 +180,7 @@ RESUMEF_NS
|
|||||||
{
|
{
|
||||||
_alloc_size = sizeof(*this);
|
_alloc_size = sizeof(*this);
|
||||||
}
|
}
|
||||||
|
public:
|
||||||
~state_t()
|
~state_t()
|
||||||
{
|
{
|
||||||
if (_has_value)
|
if (_has_value)
|
||||||
@ -187,6 +205,7 @@ RESUMEF_NS
|
|||||||
template<>
|
template<>
|
||||||
struct state_t<void> final : public state_future_t
|
struct state_t<void> final : public state_future_t
|
||||||
{
|
{
|
||||||
|
friend state_future_t;
|
||||||
using state_future_t::lock_type;
|
using state_future_t::lock_type;
|
||||||
|
|
||||||
explicit state_t(size_t alloc_size) :state_future_t()
|
explicit state_t(size_t alloc_size) :state_future_t()
|
||||||
|
@ -5,7 +5,7 @@ RESUMEF_NS
|
|||||||
void state_future_t::promise_initial_suspend(coroutine_handle<_PromiseT> handler)
|
void state_future_t::promise_initial_suspend(coroutine_handle<_PromiseT> handler)
|
||||||
{
|
{
|
||||||
assert(this->_scheduler == nullptr);
|
assert(this->_scheduler == nullptr);
|
||||||
assert(this->_coro == nullptr);
|
assert(!this->_coro);
|
||||||
|
|
||||||
this->_initor = handler;
|
this->_initor = handler;
|
||||||
this->_is_initor = initor_type::Initial;
|
this->_is_initor = initor_type::Initial;
|
||||||
@ -38,7 +38,7 @@ RESUMEF_NS
|
|||||||
this->_parent = parent_state;
|
this->_parent = parent_state;
|
||||||
this->_scheduler = sch;
|
this->_scheduler = sch;
|
||||||
}
|
}
|
||||||
if (_coro == nullptr)
|
if (!_coro)
|
||||||
this->_coro = handler;
|
this->_coro = handler;
|
||||||
|
|
||||||
if (sch != nullptr)
|
if (sch != nullptr)
|
||||||
@ -55,7 +55,7 @@ RESUMEF_NS
|
|||||||
coroutine_handle<_PromiseT> handler = coroutine_handle<_PromiseT>::from_promise(*promise);
|
coroutine_handle<_PromiseT> handler = coroutine_handle<_PromiseT>::from_promise(*promise);
|
||||||
if (!handler.done())
|
if (!handler.done())
|
||||||
{
|
{
|
||||||
if (this->_coro == nullptr)
|
if (!this->_coro)
|
||||||
this->_coro = handler;
|
this->_coro = handler;
|
||||||
scheduler_t* sch = this->get_scheduler();
|
scheduler_t* sch = this->get_scheduler();
|
||||||
if (sch != nullptr)
|
if (sch != nullptr)
|
||||||
|
@ -33,8 +33,8 @@ RESUMEF_NS
|
|||||||
scheduler_t* _scheduler;
|
scheduler_t* _scheduler;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline switch_scheduler_t via(scheduler_t* sch)
|
inline switch_scheduler_t operator co_await(scheduler_t& sch)
|
||||||
{
|
{
|
||||||
return { sch };
|
return { &sch };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,4 +22,18 @@ RESUMEF_NS
|
|||||||
struct is_generator<generator_t<_Ty, _Alloc>> : std::true_type {};
|
struct is_generator<generator_t<_Ty, _Alloc>> : std::true_type {};
|
||||||
template<class _Ty>
|
template<class _Ty>
|
||||||
constexpr bool is_generator_v = is_generator<remove_cvref_t<_Ty>>::value;
|
constexpr bool is_generator_v = is_generator<remove_cvref_t<_Ty>>::value;
|
||||||
|
|
||||||
|
template<class _PromiseT>
|
||||||
|
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_generator_v<_Ty>
|
||||||
|
|| is_awaitable_v<_Ty>
|
||||||
|
|| std::is_same_v<remove_cvref_t<_Ty>, switch_scheduler_t>
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
@ -1,91 +1,276 @@
|
|||||||
//#pragma once
|
//===----------------------------- coroutine -----------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#ifndef _LIBCPP_EXPERIMENTAL_COROUTINE
|
||||||
|
#define _LIBCPP_EXPERIMENTAL_COROUTINE
|
||||||
|
|
||||||
|
/**
|
||||||
|
experimental/coroutine synopsis
|
||||||
|
|
||||||
|
// C++next
|
||||||
|
|
||||||
namespace std {
|
namespace std {
|
||||||
namespace experimental {
|
namespace experimental {
|
||||||
template <typename R, typename...> struct coroutine_traits {
|
inline namespace coroutines_v1 {
|
||||||
using promise_type = typename R::promise_type;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Promise = void> struct coroutine_handle;
|
// 18.11.1 coroutine traits
|
||||||
|
template <typename R, typename... ArgTypes>
|
||||||
|
class coroutine_traits;
|
||||||
|
// 18.11.2 coroutine handle
|
||||||
|
template <typename Promise = void>
|
||||||
|
class coroutine_handle;
|
||||||
|
// 18.11.2.7 comparison operators:
|
||||||
|
bool operator==(coroutine_handle<> x, coroutine_handle<> y) noexcept;
|
||||||
|
bool operator!=(coroutine_handle<> x, coroutine_handle<> y) noexcept;
|
||||||
|
bool operator<(coroutine_handle<> x, coroutine_handle<> y) noexcept;
|
||||||
|
bool operator<=(coroutine_handle<> x, coroutine_handle<> y) noexcept;
|
||||||
|
bool operator>=(coroutine_handle<> x, coroutine_handle<> y) noexcept;
|
||||||
|
bool operator>(coroutine_handle<> x, coroutine_handle<> y) noexcept;
|
||||||
|
// 18.11.3 trivial awaitables
|
||||||
|
struct suspend_never;
|
||||||
|
struct suspend_always;
|
||||||
|
// 18.11.2.8 hash support:
|
||||||
|
template <class T> struct hash;
|
||||||
|
template <class P> struct hash<coroutine_handle<P>>;
|
||||||
|
|
||||||
template <> struct coroutine_handle<void> {
|
} // namespace coroutines_v1
|
||||||
static coroutine_handle from_address(void *addr) noexcept {
|
} // namespace experimental
|
||||||
coroutine_handle me;
|
} // namespace std
|
||||||
me.ptr = addr;
|
|
||||||
return me;
|
|
||||||
}
|
|
||||||
void operator()() { resume(); }
|
|
||||||
void *address() const { return ptr; }
|
|
||||||
void resume() const { __builtin_coro_resume(ptr); }
|
|
||||||
void destroy() const { __builtin_coro_destroy(ptr); }
|
|
||||||
bool done() const { return __builtin_coro_done(ptr); }
|
|
||||||
coroutine_handle &operator=(decltype(nullptr)) {
|
|
||||||
ptr = nullptr;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
coroutine_handle(decltype(nullptr)) : ptr(nullptr) {}
|
|
||||||
coroutine_handle() : ptr(nullptr) {}
|
|
||||||
// void reset() { ptr = nullptr; } // add to P0057?
|
|
||||||
explicit operator bool() const { return ptr; }
|
|
||||||
|
|
||||||
protected:
|
*/
|
||||||
void *ptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Promise> struct coroutine_handle : coroutine_handle<> {
|
#include <new>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <functional>
|
||||||
|
#include <memory> // for hash<T*>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cassert>
|
||||||
|
#include "clang_builtin.h"
|
||||||
|
|
||||||
static coroutine_handle from_address(void *addr) noexcept {
|
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||||
coroutine_handle me;
|
#pragma GCC system_header
|
||||||
me.ptr = addr;
|
#endif
|
||||||
return me;
|
|
||||||
}
|
|
||||||
coroutine_handle() {}
|
|
||||||
coroutine_handle(decltype(nullptr)) {}
|
|
||||||
coroutine_handle &operator=(decltype(nullptr)) {
|
|
||||||
ptr = nullptr;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Promise &promise() const {
|
#ifndef _LIBCPP_HAS_NO_COROUTINES
|
||||||
return *reinterpret_cast<Promise *>(
|
|
||||||
__builtin_coro_promise(ptr, alignof(Promise), false));
|
|
||||||
}
|
|
||||||
static coroutine_handle from_promise(Promise &promise) {
|
|
||||||
coroutine_handle p;
|
|
||||||
p.ptr = __builtin_coro_promise(&promise, alignof(Promise), true);
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename _PromiseT>
|
namespace std {
|
||||||
bool operator==(coroutine_handle<_PromiseT> const &_Left,
|
namespace experimental {
|
||||||
coroutine_handle<_PromiseT> const &_Right) noexcept {
|
|
||||||
return _Left.address() == _Right.address();
|
template <class _Tp, class = void>
|
||||||
|
struct __coroutine_traits_sfinae {};
|
||||||
|
|
||||||
|
template <class _Tp>
|
||||||
|
struct __coroutine_traits_sfinae<_Tp, void_t<typename _Tp::promise_type>>
|
||||||
|
{
|
||||||
|
using promise_type = typename _Tp::promise_type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename _Ret, typename... _Args>
|
||||||
|
struct coroutine_traits : public __coroutine_traits_sfinae<_Ret>
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename _Promise = void>
|
||||||
|
class coroutine_handle;
|
||||||
|
|
||||||
|
template <>
|
||||||
|
class coroutine_handle<void> {
|
||||||
|
public:
|
||||||
|
constexpr coroutine_handle() noexcept : __handle_(nullptr) {}
|
||||||
|
constexpr coroutine_handle(nullptr_t) noexcept : __handle_(nullptr) {}
|
||||||
|
coroutine_handle& operator=(nullptr_t) noexcept {
|
||||||
|
__handle_ = nullptr;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr void* address() const noexcept { return __handle_; }
|
||||||
|
constexpr explicit operator bool() const noexcept { return __handle_; }
|
||||||
|
|
||||||
|
void operator()() { resume(); }
|
||||||
|
void resume() {
|
||||||
|
__builtin_coro_resume(__handle_);
|
||||||
|
}
|
||||||
|
void destroy() {
|
||||||
|
__builtin_coro_destroy(__handle_);
|
||||||
|
}
|
||||||
|
bool done() const {
|
||||||
|
return __builtin_coro_done(__handle_);
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
static coroutine_handle from_address(void* __addr) noexcept {
|
||||||
|
coroutine_handle __tmp;
|
||||||
|
__tmp.__handle_ = __addr;
|
||||||
|
return __tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: Should from_address(nullptr) be allowed?
|
||||||
|
static coroutine_handle from_address(nullptr_t) noexcept {
|
||||||
|
return coroutine_handle(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class _Tp, bool _CallIsValid = false>
|
||||||
|
static coroutine_handle from_address(_Tp*) {
|
||||||
|
static_assert(_CallIsValid,
|
||||||
|
"coroutine_handle<void>::from_address cannot be called with "
|
||||||
|
"non-void pointers");
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool __is_suspended() const noexcept {
|
||||||
|
// FIXME actually implement a check for if the coro is suspended.
|
||||||
|
return __handle_;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class _PromiseT>
|
||||||
|
friend class coroutine_handle;
|
||||||
|
|
||||||
|
void* __handle_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 18.11.2.7 comparison operators:
|
||||||
|
inline bool operator==(coroutine_handle<> __x, coroutine_handle<> __y) noexcept {
|
||||||
|
return __x.address() == __y.address();
|
||||||
|
}
|
||||||
|
inline bool operator!=(coroutine_handle<> __x, coroutine_handle<> __y) noexcept {
|
||||||
|
return !(__x == __y);
|
||||||
|
}
|
||||||
|
inline bool operator<(coroutine_handle<> __x, coroutine_handle<> __y) noexcept {
|
||||||
|
return less<void*>()(__x.address(), __y.address());
|
||||||
|
}
|
||||||
|
inline bool operator>(coroutine_handle<> __x, coroutine_handle<> __y) noexcept {
|
||||||
|
return __y < __x;
|
||||||
|
}
|
||||||
|
inline bool operator<=(coroutine_handle<> __x, coroutine_handle<> __y) noexcept {
|
||||||
|
return !(__x > __y);
|
||||||
|
}
|
||||||
|
inline bool operator>=(coroutine_handle<> __x, coroutine_handle<> __y) noexcept {
|
||||||
|
return !(__x < __y);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename _Promise>
|
||||||
|
class coroutine_handle : public coroutine_handle<> {
|
||||||
|
using _Base = coroutine_handle<>;
|
||||||
|
public:
|
||||||
|
#ifndef _LIBCPP_CXX03_LANG
|
||||||
|
// 18.11.2.1 construct/reset
|
||||||
|
using coroutine_handle<>::coroutine_handle;
|
||||||
|
#else
|
||||||
|
coroutine_handle() noexcept : _Base() {}
|
||||||
|
coroutine_handle(nullptr_t) noexcept : _Base(nullptr) {}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
coroutine_handle& operator=(nullptr_t) noexcept {
|
||||||
|
_Base::operator=(nullptr);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
_Promise& promise() const {
|
||||||
|
return *static_cast<_Promise*>(
|
||||||
|
__builtin_coro_promise(this->__handle_, alignof(_Promise), false));
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
static coroutine_handle from_address(void* __addr) noexcept {
|
||||||
|
coroutine_handle __tmp;
|
||||||
|
__tmp.__handle_ = __addr;
|
||||||
|
return __tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: this overload isn't required by the standard but is needed so
|
||||||
|
// the deleted _Promise* overload doesn't make from_address(nullptr)
|
||||||
|
// ambiguous.
|
||||||
|
// FIXME: should from_address work with nullptr?
|
||||||
|
static coroutine_handle from_address(nullptr_t) noexcept {
|
||||||
|
return coroutine_handle(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class _Tp, bool _CallIsValid = false>
|
||||||
|
static coroutine_handle from_address(_Tp*) {
|
||||||
|
static_assert(_CallIsValid,
|
||||||
|
"coroutine_handle<promise_type>::from_address cannot be called with "
|
||||||
|
"non-void pointers");
|
||||||
|
}
|
||||||
|
|
||||||
|
template <bool _CallIsValid = false>
|
||||||
|
static coroutine_handle from_address(_Promise*) {
|
||||||
|
static_assert(_CallIsValid,
|
||||||
|
"coroutine_handle<promise_type>::from_address cannot be used with "
|
||||||
|
"pointers to the coroutine's promise type; use 'from_promise' instead");
|
||||||
|
}
|
||||||
|
|
||||||
|
static coroutine_handle from_promise(_Promise& __promise) noexcept {
|
||||||
|
typedef typename remove_cv<_Promise>::type _RawPromise;
|
||||||
|
coroutine_handle __tmp;
|
||||||
|
__tmp.__handle_ = __builtin_coro_promise(
|
||||||
|
std::addressof(const_cast<_RawPromise&>(__promise)),
|
||||||
|
alignof(_Promise), true);
|
||||||
|
return __tmp;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#if __has_builtin(__builtin_coro_noop)
|
||||||
|
struct noop_coroutine_promise {};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
class coroutine_handle<noop_coroutine_promise>
|
||||||
|
: public coroutine_handle<> {
|
||||||
|
using _Base = coroutine_handle<>;
|
||||||
|
using _Promise = noop_coroutine_promise;
|
||||||
|
public:
|
||||||
|
_Promise& promise() const {
|
||||||
|
return *static_cast<_Promise*>(
|
||||||
|
__builtin_coro_promise(this->__handle_, alignof(_Promise), false));
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr explicit operator bool() const noexcept { return true; }
|
||||||
|
constexpr bool done() const noexcept { return false; }
|
||||||
|
|
||||||
|
constexpr void operator()() const noexcept {}
|
||||||
|
constexpr void resume() const noexcept {}
|
||||||
|
constexpr void destroy() const noexcept {}
|
||||||
|
private:
|
||||||
|
friend coroutine_handle<noop_coroutine_promise> noop_coroutine() noexcept;
|
||||||
|
coroutine_handle() noexcept {
|
||||||
|
this->__handle_ = __builtin_coro_noop();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
using noop_coroutine_handle = coroutine_handle<noop_coroutine_promise>;
|
||||||
|
|
||||||
|
inline noop_coroutine_handle noop_coroutine() noexcept {
|
||||||
|
return noop_coroutine_handle();
|
||||||
|
}
|
||||||
|
#endif // __has_builtin(__builtin_coro_noop)
|
||||||
|
|
||||||
|
struct suspend_never {
|
||||||
|
bool await_ready() const noexcept { return true; }
|
||||||
|
void await_suspend(coroutine_handle<>) const noexcept {}
|
||||||
|
void await_resume() const noexcept {}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct suspend_always {
|
||||||
|
bool await_ready() const noexcept { return false; }
|
||||||
|
void await_suspend(coroutine_handle<>) const noexcept {}
|
||||||
|
void await_resume() const noexcept {}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class _Tp>
|
||||||
|
struct hash<experimental::coroutine_handle<_Tp> > {
|
||||||
|
using __arg_type = experimental::coroutine_handle<_Tp>;
|
||||||
|
size_t operator()(__arg_type const& __v) const noexcept
|
||||||
|
{
|
||||||
|
return hash<void*>()(__v.address());
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename _PromiseT>
|
#endif // !defined(_LIBCPP_HAS_NO_COROUTINES)
|
||||||
bool operator!=(coroutine_handle<_PromiseT> const &_Left,
|
|
||||||
coroutine_handle<_PromiseT> const &_Right) noexcept {
|
|
||||||
return !(_Left == _Right);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct suspend_always {
|
#endif /* _LIBCPP_EXPERIMENTAL_COROUTINE */
|
||||||
bool await_ready() { return false; }
|
|
||||||
void await_suspend(coroutine_handle<>) {}
|
|
||||||
void await_resume() {}
|
|
||||||
};
|
|
||||||
struct suspend_never {
|
|
||||||
bool await_ready() { return true; }
|
|
||||||
void await_suspend(coroutine_handle<>) {}
|
|
||||||
void await_resume() {}
|
|
||||||
};
|
|
||||||
struct suspend_if {
|
|
||||||
bool _Ready;
|
|
||||||
|
|
||||||
explicit suspend_if(bool _Condition) : _Ready(!_Condition) {}
|
|
||||||
bool await_ready() { return _Ready; }
|
|
||||||
void await_suspend(coroutine_handle<>) {}
|
|
||||||
void await_resume() {}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
@ -19,7 +19,9 @@ future_t<> test_channel_read(const channel_t<std::string> & c)
|
|||||||
|
|
||||||
for (size_t i = 0; i < 10; ++i)
|
for (size_t i = 0; i < 10; ++i)
|
||||||
{
|
{
|
||||||
|
#ifndef __clang__
|
||||||
try
|
try
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
auto val = co_await c.read();
|
auto val = co_await c.read();
|
||||||
//auto val = co_await c; //第二种从channel读出数据的方法。利用重载operator co_await(),而不是c是一个awaitable_t。
|
//auto val = co_await c; //第二种从channel读出数据的方法。利用重载operator co_await(),而不是c是一个awaitable_t。
|
||||||
@ -31,11 +33,13 @@ future_t<> test_channel_read(const channel_t<std::string> & c)
|
|||||||
#endif
|
#endif
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
}
|
}
|
||||||
|
#ifndef __clang__
|
||||||
catch (resumef::channel_exception& e)
|
catch (resumef::channel_exception& e)
|
||||||
{
|
{
|
||||||
//MAX_CHANNEL_QUEUE=0,并且先读后写,会触发read_before_write异常
|
//MAX_CHANNEL_QUEUE=0,并且先读后写,会触发read_before_write异常
|
||||||
std::cout << e.what() << std::endl;
|
std::cout << e.what() << std::endl;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
co_await sleep_for(50ms);
|
co_await sleep_for(50ms);
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,9 @@ future_t<> test_channel_consumer(const channel_t<std::string> & c, size_t cnt)
|
|||||||
{
|
{
|
||||||
for (size_t i = 0; i < cnt; ++i)
|
for (size_t i = 0; i < cnt; ++i)
|
||||||
{
|
{
|
||||||
|
#ifndef __clang__
|
||||||
try
|
try
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
auto val = co_await c.read();
|
auto val = co_await c.read();
|
||||||
++gcounter;
|
++gcounter;
|
||||||
@ -33,12 +35,14 @@ future_t<> test_channel_consumer(const channel_t<std::string> & c, size_t cnt)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
#ifndef __clang__
|
||||||
catch (channel_exception& e)
|
catch (channel_exception& e)
|
||||||
{
|
{
|
||||||
//MAX_CHANNEL_QUEUE=0,并且先读后写,会触发read_before_write异常
|
//MAX_CHANNEL_QUEUE=0,并且先读后写,会触发read_before_write异常
|
||||||
scoped_lock<std::mutex> __lock(cout_mutex);
|
scoped_lock<std::mutex> __lock(cout_mutex);
|
||||||
std::cout << e.what() << std::endl;
|
std::cout << e.what() << std::endl;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#if OUTPUT_DEBUG
|
#if OUTPUT_DEBUG
|
||||||
co_await sleep_for(50ms);
|
co_await sleep_for(50ms);
|
||||||
@ -109,5 +113,4 @@ void resumable_main_channel_mult_thread()
|
|||||||
write_th.join();
|
write_th.join();
|
||||||
|
|
||||||
std::cout << "OK: counter = " << gcounter.load() << std::endl;
|
std::cout << "OK: counter = " << gcounter.load() << std::endl;
|
||||||
(void)_getch();
|
|
||||||
}
|
}
|
||||||
|
@ -53,11 +53,14 @@ future_t<> test_signal_exception()
|
|||||||
{
|
{
|
||||||
for (intptr_t i = 10; i >= 0; --i)
|
for (intptr_t i = 10; i >= 0; --i)
|
||||||
{
|
{
|
||||||
|
#ifndef __clang__
|
||||||
try
|
try
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
auto r = co_await async_signal_exception2(i);
|
auto r = co_await async_signal_exception2(i);
|
||||||
std::cout << "result is " << r << std::endl;
|
std::cout << "result is " << r << std::endl;
|
||||||
}
|
}
|
||||||
|
#ifndef __clang__
|
||||||
catch (const std::exception& e)
|
catch (const std::exception& e)
|
||||||
{
|
{
|
||||||
std::cout << "exception signal : " << e.what() << std::endl;
|
std::cout << "exception signal : " << e.what() << std::endl;
|
||||||
@ -66,6 +69,7 @@ future_t<> test_signal_exception()
|
|||||||
{
|
{
|
||||||
std::cout << "exception signal : who knows?" << std::endl;
|
std::cout << "exception signal : who knows?" << std::endl;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -394,7 +394,9 @@ void resumable_main_modern_cb()
|
|||||||
//支持librf的用法
|
//支持librf的用法
|
||||||
GO
|
GO
|
||||||
{
|
{
|
||||||
|
#ifndef __clang__
|
||||||
try
|
try
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
int val = co_await add_async(1, 2, use_librf);
|
int val = co_await add_async(1, 2, use_librf);
|
||||||
std::cout << val << std::endl;
|
std::cout << val << std::endl;
|
||||||
@ -409,6 +411,7 @@ void resumable_main_modern_cb()
|
|||||||
|
|
||||||
std::cout << result << std::endl;
|
std::cout << result << std::endl;
|
||||||
}
|
}
|
||||||
|
#ifndef __clang__
|
||||||
catch (const std::exception& e)
|
catch (const std::exception& e)
|
||||||
{
|
{
|
||||||
std::cout << "exception signal : " << e.what() << std::endl;
|
std::cout << "exception signal : " << e.what() << std::endl;
|
||||||
@ -417,6 +420,7 @@ void resumable_main_modern_cb()
|
|||||||
{
|
{
|
||||||
std::cout << "exception signal : who knows?" << std::endl;
|
std::cout << "exception signal : who knows?" << std::endl;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
resumef::this_scheduler()->run_until_notask();
|
resumef::this_scheduler()->run_until_notask();
|
||||||
|
@ -30,7 +30,7 @@ auto yield_switch(intptr_t coro) -> resumef::generator_t<intptr_t>
|
|||||||
{
|
{
|
||||||
for (intptr_t i = 0; i < N / coro; ++i)
|
for (intptr_t i = 0; i < N / coro; ++i)
|
||||||
co_yield i;
|
co_yield i;
|
||||||
return N / coro;
|
co_return N / coro;
|
||||||
}
|
}
|
||||||
|
|
||||||
void resumable_switch(intptr_t coro, size_t idx)
|
void resumable_switch(intptr_t coro, size_t idx)
|
||||||
|
@ -59,7 +59,7 @@ static future_t<> resumable_get_long(int64_t val, channel_t<bool> & c_done)
|
|||||||
{
|
{
|
||||||
std::cout << "thread = " << std::this_thread::get_id() << ", value = " << val << std::endl;
|
std::cout << "thread = " << std::this_thread::get_id() << ", value = " << val << std::endl;
|
||||||
|
|
||||||
co_await via(sch_in_thread);
|
co_await *sch_in_thread;
|
||||||
val = co_await async_get_long(val);
|
val = co_await async_get_long(val);
|
||||||
std::cout << "thread = " << std::this_thread::get_id() << ", value = " << val << std::endl;
|
std::cout << "thread = " << std::this_thread::get_id() << ", value = " << val << std::endl;
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
using namespace resumef;
|
using namespace resumef;
|
||||||
|
|
||||||
auto test_yield_int() -> generator_t<int>
|
generator_t<int> test_yield_int()
|
||||||
{
|
{
|
||||||
std::cout << "1 will yield return" << std::endl;
|
std::cout << "1 will yield return" << std::endl;
|
||||||
co_yield 1;
|
co_yield 1;
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
|
|
||||||
#include "librf.h"
|
#include "librf.h"
|
||||||
#include <experimental/resumable>
|
|
||||||
#include <experimental/generator>
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
extern void resumable_main_yield_return();
|
extern void resumable_main_yield_return();
|
||||||
@ -34,33 +32,36 @@ int main(int argc, const char* argv[])
|
|||||||
(void)argc;
|
(void)argc;
|
||||||
(void)argv;
|
(void)argv;
|
||||||
resumable_main_layout();
|
resumable_main_layout();
|
||||||
|
return 0;
|
||||||
|
|
||||||
//if (argc > 1)
|
//if (argc > 1)
|
||||||
// resumable_main_benchmark_asio_client(atoi(argv[1]));
|
// resumable_main_benchmark_asio_client(atoi(argv[1]));
|
||||||
//else
|
//else
|
||||||
// resumable_main_benchmark_asio_server();
|
// resumable_main_benchmark_asio_server();
|
||||||
|
|
||||||
//resumable_main_cb();
|
resumable_main_cb();
|
||||||
//resumable_main_layout();
|
resumable_main_layout();
|
||||||
//resumable_main_modern_cb();
|
resumable_main_modern_cb();
|
||||||
//resumable_main_suspend_always();
|
resumable_main_suspend_always();
|
||||||
//resumable_main_yield_return();
|
resumable_main_yield_return();
|
||||||
//resumable_main_resumable();
|
//resumable_main_resumable();
|
||||||
//resumable_main_routine();
|
resumable_main_routine();
|
||||||
//resumable_main_exception();
|
resumable_main_exception();
|
||||||
//resumable_main_dynamic_go();
|
resumable_main_dynamic_go();
|
||||||
//resumable_main_multi_thread();
|
//resumable_main_multi_thread();
|
||||||
//resumable_main_timer();
|
resumable_main_timer();
|
||||||
//resumable_main_benchmark_mem();
|
//resumable_main_benchmark_mem();
|
||||||
//resumable_main_mutex();
|
resumable_main_mutex();
|
||||||
//resumable_main_event();
|
resumable_main_event();
|
||||||
//resumable_main_event_timeout();
|
resumable_main_event_timeout();
|
||||||
//resumable_main_channel();
|
resumable_main_channel();
|
||||||
//resumable_main_channel_mult_thread();
|
resumable_main_channel_mult_thread();
|
||||||
//resumable_main_sleep();
|
resumable_main_sleep();
|
||||||
//resumable_main_when_all();
|
resumable_main_when_all();
|
||||||
//resumable_main_switch_scheduler();
|
resumable_main_switch_scheduler();
|
||||||
//benchmark_main_channel_passing_next();
|
//benchmark_main_channel_passing_next();
|
||||||
|
|
||||||
|
std::cout << "ALL OK!" << std::endl;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,7 @@
|
|||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||||
<ConfigurationType>Application</ConfigurationType>
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
<UseDebugLibraries>false</UseDebugLibraries>
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
<PlatformToolset>v142</PlatformToolset>
|
<PlatformToolset>ClangCL</PlatformToolset>
|
||||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
<CharacterSet>NotSet</CharacterSet>
|
<CharacterSet>NotSet</CharacterSet>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
@ -170,7 +170,10 @@
|
|||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="..\benchmark\benchmark_asio_echo.cpp" />
|
<ClCompile Include="..\benchmark\benchmark_asio_echo.cpp">
|
||||||
|
<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_async_mem.cpp" />
|
||||||
<ClCompile Include="..\benchmark\benchmark_channel_passing_next.cpp" />
|
<ClCompile Include="..\benchmark\benchmark_channel_passing_next.cpp" />
|
||||||
<ClCompile Include="..\librf\src\event.cpp" />
|
<ClCompile Include="..\librf\src\event.cpp" />
|
||||||
@ -181,24 +184,58 @@
|
|||||||
<ClCompile Include="..\librf\src\state.cpp" />
|
<ClCompile Include="..\librf\src\state.cpp" />
|
||||||
<ClCompile Include="..\librf\src\timer.cpp" />
|
<ClCompile Include="..\librf\src\timer.cpp" />
|
||||||
<ClCompile Include="..\librf\src\when.cpp" />
|
<ClCompile Include="..\librf\src\when.cpp" />
|
||||||
<ClCompile Include="..\tutorial\test_async_cb.cpp" />
|
<ClCompile Include="..\tutorial\test_async_cb.cpp">
|
||||||
<ClCompile Include="..\tutorial\test_async_channel.cpp" />
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||||
<ClCompile Include="..\tutorial\test_async_channel_mult_thread.cpp" />
|
</ClCompile>
|
||||||
<ClCompile Include="..\tutorial\test_async_dynamic_go.cpp" />
|
<ClCompile Include="..\tutorial\test_async_channel.cpp">
|
||||||
<ClCompile Include="..\tutorial\test_async_event.cpp" />
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||||
<ClCompile Include="..\tutorial\test_async_event_timeout.cpp" />
|
</ClCompile>
|
||||||
<ClCompile Include="..\tutorial\test_async_exception.cpp" />
|
<ClCompile Include="..\tutorial\test_async_channel_mult_thread.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\tutorial\test_async_dynamic_go.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\tutorial\test_async_event.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\tutorial\test_async_event_timeout.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\tutorial\test_async_exception.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="..\tutorial\test_async_memory_layout.cpp" />
|
<ClCompile Include="..\tutorial\test_async_memory_layout.cpp" />
|
||||||
<ClCompile Include="..\tutorial\test_async_modern_cb.cpp" />
|
<ClCompile Include="..\tutorial\test_async_modern_cb.cpp">
|
||||||
<ClCompile Include="..\tutorial\test_async_multi_thread.cpp" />
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||||
<ClCompile Include="..\tutorial\test_async_mutex.cpp" />
|
</ClCompile>
|
||||||
<ClCompile Include="..\tutorial\test_async_resumable.cpp" />
|
<ClCompile Include="..\tutorial\test_async_multi_thread.cpp">
|
||||||
<ClCompile Include="..\tutorial\test_async_routine.cpp" />
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||||
<ClCompile Include="..\tutorial\test_async_sleep.cpp" />
|
</ClCompile>
|
||||||
<ClCompile Include="..\tutorial\test_async_suspend_always.cpp" />
|
<ClCompile Include="..\tutorial\test_async_mutex.cpp">
|
||||||
<ClCompile Include="..\tutorial\test_async_switch_scheduler.cpp" />
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||||
<ClCompile Include="..\tutorial\test_async_timer.cpp" />
|
</ClCompile>
|
||||||
<ClCompile Include="..\tutorial\test_async_when_all.cpp" />
|
<ClCompile Include="..\tutorial\test_async_resumable.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\tutorial\test_async_routine.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\tutorial\test_async_sleep.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\tutorial\test_async_suspend_always.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\tutorial\test_async_switch_scheduler.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\tutorial\test_async_timer.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\tutorial\test_async_when_all.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="..\tutorial\test_async_yield_return.cpp" />
|
<ClCompile Include="..\tutorial\test_async_yield_return.cpp" />
|
||||||
<ClCompile Include="librf.cpp">
|
<ClCompile Include="librf.cpp">
|
||||||
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Default</BasicRuntimeChecks>
|
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Default</BasicRuntimeChecks>
|
||||||
@ -226,6 +263,7 @@
|
|||||||
<ClInclude Include="..\librf\src\state.h" />
|
<ClInclude Include="..\librf\src\state.h" />
|
||||||
<ClInclude Include="..\librf\src\switch_scheduler.h" />
|
<ClInclude Include="..\librf\src\switch_scheduler.h" />
|
||||||
<ClInclude Include="..\librf\src\timer.h" />
|
<ClInclude Include="..\librf\src\timer.h" />
|
||||||
|
<ClInclude Include="..\librf\src\unix\clang_builtin.h" />
|
||||||
<ClInclude Include="..\librf\src\unix\coroutine.h" />
|
<ClInclude Include="..\librf\src\unix\coroutine.h" />
|
||||||
<ClInclude Include="..\librf\src\utils.h" />
|
<ClInclude Include="..\librf\src\utils.h" />
|
||||||
<ClInclude Include="..\librf\src\when.h" />
|
<ClInclude Include="..\librf\src\when.h" />
|
||||||
|
@ -186,6 +186,9 @@
|
|||||||
<ClInclude Include="..\librf\src\switch_scheduler.h">
|
<ClInclude Include="..\librf\src\switch_scheduler.h">
|
||||||
<Filter>librf\src</Filter>
|
<Filter>librf\src</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\librf\src\unix\clang_builtin.h">
|
||||||
|
<Filter>librf\src\unix</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="..\librf\src\asio_task_1.12.0.inl">
|
<None Include="..\librf\src\asio_task_1.12.0.inl">
|
||||||
|
Loading…
Reference in New Issue
Block a user