Browse Source

优化一点内存占用空间和性能

更好的兼容clang
版本升级到2.2.1
tags/v2.9.7
tearshark 4 years ago
parent
commit
3ba9a56cae

+ 1
- 1
benchmark/benchmark_asio_echo.cpp View File

@@ -275,7 +275,7 @@ private:
{
auto self = this->shared_from_this();
asio::async_connect(socket_, endpoint_,
[this, self](std::error_code ec, tcp::resolver::iterator iter)
[this, self](std::error_code ec, tcp::resolver::iterator )
{
if (!ec)
{

+ 1
- 1
benchmark/benchmark_async_mem.cpp View File

@@ -17,7 +17,7 @@ void resumable_main_benchmark_mem()
for (size_t i = 0; i < N; ++i)
{
go[=]()->resumef::future_t<size_t>
go[=]()->resumef::generator_t<size_t>
{
for (size_t k = 0; k < 10; ++k)
{

+ 3
- 2
librf/src/awaitable.h View File

@@ -55,9 +55,10 @@ RESUMEF_NS
using typename awaitable_impl_t<_Ty>::value_type;
using awaitable_impl_t<_Ty>::awaitable_impl_t;

void set_value(value_type value) const
template<class U>
void set_value(U&& value) const
{
this->_state->set_value(std::move(value));
this->_state->set_value(std::forward<U>(value));
this->_state = nullptr;
}
};

+ 1
- 1
librf/src/def.h View File

@@ -1,6 +1,6 @@
#pragma once
#define LIB_RESUMEF_VERSION 20200 // 2.2.0
#define LIB_RESUMEF_VERSION 20201 // 2.2.1
#if defined(RESUMEF_MODULE_EXPORT)
#define RESUMEF_NS export namespace resumef

+ 17
- 0
librf/src/future.h View File

@@ -40,3 +40,20 @@ RESUMEF_NS
};
}
namespace std {
namespace experimental {
/*If the coroutine is defined as task<float> foo(std::string x, bool flag);,
then its Promise type is std::coroutine_traits<task<float>, std::string, bool>::promise_type.
If the coroutine is a non-static member function, such as task<void> my_class::method1(int x) const;,
its Promise type is std::coroutine_traits<task<void>, const my_class&, int>::promise_type.
*/
template <typename _Ty, typename... Args>
struct coroutine_traits<resumef::future_t<_Ty>, Args...>
{
typedef resumef::promise_t<_Ty> promise_type;
};
}
} // namespace std::experimental

+ 30
- 10
librf/src/generator.h View File

@@ -115,22 +115,22 @@ RESUMEF_NS
}
promise_type(promise_type&& _Right) noexcept = default;
promise_type& operator = (promise_type&& _Right) noexcept = default;
promise_type(const promise_type&) = delete;
promise_type& operator = (const promise_type&) = delete;
promise_type(const promise_type&) = default;
promise_type& operator = (const promise_type&) = default;
promise_type& get_return_object()
generator_t get_return_object()
{
return *this;
return generator_t{ *this };
}
bool initial_suspend()
{
return (true);
return true;
}
bool final_suspend()
{
return (true);
return true;
}
void yield_value(_Ty const& _Value)
@@ -138,17 +138,28 @@ RESUMEF_NS
_CurrentValue = std::addressof(_Value);
}
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>>
void return_value(_Ty const& _Value)
{
_CurrentValue = std::addressof(_Value);
}
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>>
void return_value()
{
_CurrentValue = nullptr;
}
void set_exception(std::exception_ptr e)
{
std::terminate();
}
#ifdef __clang__
void unhandled_exception()
{
std::terminate();
}
#endif
template <typename _Uty>
_Uty&& await_transform(_Uty&& _Whatever)
{
@@ -198,7 +209,6 @@ RESUMEF_NS
*reinterpret_cast<uint32_t*>(_Ptr) = static_cast<uint32_t>(_Size + _State_size);
_Alloc_char _Al;
state_type* st = reinterpret_cast<state_type*>(static_cast<char*>(_Ptr) - _State_size);
st->unlock();
}
@@ -230,7 +240,6 @@ RESUMEF_NS
generator_t() = default;
generator_t(generator_t const&) = delete;
generator_t& operator=(generator_t const&) = delete;
generator_t(generator_t&& right_) noexcept
@@ -270,3 +279,14 @@ RESUMEF_NS
#pragma pop_macro("new")
#pragma pack(pop)
namespace std {
namespace experimental {
template <typename _Ty, typename _Alloc, typename... Args>
struct coroutine_traits<resumef::generator_t<_Ty, _Alloc>, Args...>
{
typedef typename resumef::generator_t<_Ty, _Alloc>::promise_type promise_type;
};
}
} // namespace std::experimental

+ 11
- 5
librf/src/promise.h View File

@@ -33,7 +33,7 @@ RESUMEF_NS
suspend_on_final final_suspend() noexcept;
void set_exception(std::exception_ptr e);
#ifdef __clang__
void unhandled_exception();
void unhandled_exception(); //If the coroutine ends with an uncaught exception, it performs the following:
#endif
future_type get_return_object();
void cancellation_requested();
@@ -45,6 +45,11 @@ RESUMEF_NS
assert(_Size >= sizeof(uint32_t) && _Size < (std::numeric_limits<uint32_t>::max)() - sizeof(_State_size));

_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;
@@ -67,7 +72,6 @@ RESUMEF_NS
size_t _State_size = _Align_size<state_type>();
assert(_Size >= sizeof(uint32_t) && _Size < (std::numeric_limits<uint32_t>::max)() - sizeof(_State_size));

_Alloc_char _Al;
state_type* st = reinterpret_cast<state_type*>(static_cast<char*>(_Ptr) - _State_size);
st->unlock();
}
@@ -79,8 +83,10 @@ RESUMEF_NS
using typename promise_impl_t<_Ty>::value_type;
using promise_impl_t<_Ty>::get_return_object;

void return_value(value_type val);
void yield_value(value_type val);
template<class U>
void return_value(U&& val); //co_return val
template<class U>
void yield_value(U&& val);
};

template<>
@@ -88,7 +94,7 @@ RESUMEF_NS
{
using promise_impl_t<void>::get_return_object;

void return_void();
void return_void(); //co_return;
void yield_value();
};


+ 19
- 13
librf/src/promise.inl View File

@@ -1,10 +1,14 @@

RESUMEF_NS
{
/*
Note: the awaiter object is part of coroutine state (as a temporary whose lifetime crosses a suspension point)
and is destroyed before the co_await expression finishes.
It can be used to maintain per-operation state as required by some async I/O APIs without resorting to additional heap allocations.
*/

struct suspend_on_initial
{
state_future_t* _state;

inline bool await_ready() noexcept
{
return false;
@@ -12,17 +16,16 @@ RESUMEF_NS
template<class _PromiseT, typename = std::enable_if_t<is_promise_v<_PromiseT>>>
inline void await_suspend(coroutine_handle<_PromiseT> handler) noexcept
{
_PromiseT& promise = handler.promise();
auto* _state = promise.get_state();
_state->promise_initial_suspend(handler);
}
inline void await_resume() noexcept
{
_state->promise_await_resume();
}
};
struct suspend_on_final
{
state_future_t* _state;

inline bool await_ready() noexcept
{
return false;
@@ -30,24 +33,25 @@ RESUMEF_NS
template<class _PromiseT, typename = std::enable_if_t<is_promise_v<_PromiseT>>>
inline void await_suspend(coroutine_handle<_PromiseT> handler) noexcept
{
_PromiseT& promise = handler.promise();
auto* _state = promise.get_state();
_state->promise_final_suspend(handler);
}
inline void await_resume() noexcept
{
_state->promise_await_resume();
}
};

template <typename _Ty>
inline suspend_on_initial promise_impl_t<_Ty>::initial_suspend() noexcept
{
return { this->get_state() };
return {};
}

template <typename _Ty>
inline suspend_on_final promise_impl_t<_Ty>::final_suspend() noexcept
{
return { this->get_state() };
return {};
}

template <typename _Ty>
@@ -60,7 +64,7 @@ RESUMEF_NS
template <typename _Ty>
inline void promise_impl_t<_Ty>::unhandled_exception()
{
std::terminate();
this->get_state()->set_exception(std::current_exception());
}
#endif

@@ -78,15 +82,17 @@ RESUMEF_NS


template<class _Ty>
inline void promise_t<_Ty>::return_value(value_type val)
template<class U>
inline void promise_t<_Ty>::return_value(U&& val)
{
this->get_state()->set_value(std::move(val));
this->get_state()->set_value(std::forward<U>(val));
}

template<class _Ty>
inline void promise_t<_Ty>::yield_value(value_type val)
template<class U>
inline void promise_t<_Ty>::yield_value(U&& val)
{
this->get_state()->promise_yield_value(this, std::move(val));
this->get_state()->promise_yield_value(this, std::forward<U>(val));
}

inline void promise_t<void>::return_void()

+ 9
- 9
librf/src/state.cpp View File

@@ -88,13 +88,14 @@ RESUMEF_NS
{
std::unique_lock<lock_type> __guard(_mtx);
if (_initor != nullptr && _is_initor)
if (_is_initor == initor_type::Initial)
{
coroutine_handle<> handler = _initor;
_initor = nullptr;
assert(_initor != nullptr);
_is_initor = initor_type::None;
__guard.unlock();
handler.resume();
_initor.resume();
return;
}
@@ -108,13 +109,12 @@ RESUMEF_NS
return;
}
if (_initor != nullptr && !_is_initor)
if (_is_initor == initor_type::Final)
{
coroutine_handle<> handler = _initor;
_initor = nullptr;
_is_initor = initor_type::None;
__guard.unlock();
handler.destroy();
_initor.destroy();
return;
}
}
@@ -122,7 +122,7 @@ RESUMEF_NS
bool state_future_t::has_handler() const
{
scoped_lock<lock_type> __guard(_mtx);
return _coro != nullptr || _initor != nullptr;
return _coro != nullptr || _is_initor != initor_type::None;
}
bool state_future_t::is_ready() const

+ 20
- 17
librf/src/state.h View File

@@ -71,6 +71,12 @@ RESUMEF_NS
struct state_future_t : public state_base_t
{
enum struct initor_type : uint8_t
{
None,
Initial,
Final
};
typedef std::recursive_mutex lock_type;
protected:
mutable lock_type _mtx;
@@ -83,7 +89,7 @@ RESUMEF_NS
uint32_t _alloc_size;
bool _has_value = false;
bool _is_awaitor;
bool _is_initor = false;
initor_type _is_initor = initor_type::None;
public:
state_future_t()
{
@@ -138,7 +144,6 @@ RESUMEF_NS
template<class _PromiseT, typename = std::enable_if_t<is_promise_v<_PromiseT>>>
void promise_initial_suspend(coroutine_handle<_PromiseT> handler);
void promise_await_resume();
template<class _PromiseT, typename = std::enable_if_t<is_promise_v<_PromiseT>>>
void promise_final_suspend(coroutine_handle<_PromiseT> handler);
};
@@ -157,28 +162,26 @@ RESUMEF_NS
{
_alloc_size = sizeof(*this);
}
private:
union union_value_type
{
value_type _value;
char _[1];
union_value_type() {}
~union_value_type() {}
};
union_value_type uv;
~state_t()
{
if (_has_value)
uv._value.~value_type();
cast_value_ptr()->~value_type();
}
public:
auto future_await_resume() -> value_type;
template<class _PromiseT, typename = std::enable_if_t<is_promise_v<_PromiseT>>>
void promise_yield_value(_PromiseT* promise, value_type val);
template<class _PromiseT, typename U, typename = std::enable_if_t<is_promise_v<_PromiseT>>>
void promise_yield_value(_PromiseT* promise, U&& val);
template<typename U>
void set_value(U&& val);
private:
value_type * cast_value_ptr()
{
return static_cast<value_type*>(static_cast<void*>(_value));
}
void set_value(value_type val);
alignas(value_type) unsigned char _value[sizeof(value_type)];
};
template<>

+ 12
- 24
librf/src/state.inl View File

@@ -4,19 +4,11 @@ RESUMEF_NS
template<class _PromiseT, typename _Enable>
void state_future_t::promise_initial_suspend(coroutine_handle<_PromiseT> handler)
{
_PromiseT& promise = handler.promise();

state_base_t* parent_state = promise.get_state();
(void)parent_state;
assert(this == parent_state);
assert(this->_scheduler == nullptr);
assert(this->_coro == nullptr);
this->_initor = handler;
this->_is_initor = true;
}

inline void state_future_t::promise_await_resume()
{
this->_initor = handler;
this->_is_initor = initor_type::Initial;
}

template<class _PromiseT, typename _Enable>
@@ -24,13 +16,8 @@ RESUMEF_NS
{
scoped_lock<lock_type> __guard(this->_mtx);

_PromiseT& promise = handler.promise();

state_base_t* parent_state = promise.get_state();
(void)parent_state;
assert(this == parent_state);
this->_initor = handler;
this->_is_initor = false;
this->_is_initor = initor_type::Final;

scheduler_t* sch = this->get_scheduler();
assert(sch != nullptr);
@@ -77,19 +64,19 @@ RESUMEF_NS
}

template<typename _Ty>
template<class _PromiseT, typename _Enable >
void state_t<_Ty>::promise_yield_value(_PromiseT* promise, _Ty val)
template<class _PromiseT, typename U, typename _Enable >
void state_t<_Ty>::promise_yield_value(_PromiseT* promise, U&& val)
{
scoped_lock<lock_type> __guard(this->_mtx);

if (this->_has_value)
{
this->uv._value = std::move(val);
*this->cast_value_ptr() = std::forward<U>(val);
}
else
{
new (this->cast_value_ptr()) value_type(std::forward<U>(val));
this->_has_value = true;
new(&this->uv._value) value_type(std::move(val));
}

coroutine_handle<_PromiseT> handler = coroutine_handle<_PromiseT>::from_promise(*promise);
@@ -112,22 +99,23 @@ RESUMEF_NS
if (!this->_has_value)
std::rethrow_exception(std::make_exception_ptr(future_exception{error_code::not_ready}));

return std::move(this->uv._value);
return std::move(*this->cast_value_ptr());
}

template<typename _Ty>
void state_t<_Ty>::set_value(value_type val)
template<typename U>
void state_t<_Ty>::set_value(U&& val)
{
scoped_lock<lock_type> __guard(this->_mtx);

if (this->_has_value)
{
this->uv._value = std::move(val);
*this->cast_value_ptr() = std::forward<U>(val);
}
else
{
new (this->cast_value_ptr()) value_type(std::forward<U>(val));
this->_has_value = true;
new(&this->uv._value) value_type(std::move(val));
}

scheduler_t* sch = this->get_scheduler();

+ 1
- 1
tutorial/test_async_channel.cpp View File

@@ -31,7 +31,7 @@ future_t<> test_channel_read(const channel_t<std::string> & c)
#endif
std::cout << std::endl;
}
catch (channel_exception e)
catch (resumef::channel_exception& e)
{
//MAX_CHANNEL_QUEUE=0,并且先读后写,会触发read_before_write异常
std::cout << e.what() << std::endl;

+ 1
- 1
tutorial/test_async_channel_mult_thread.cpp View File

@@ -33,7 +33,7 @@ future_t<> test_channel_consumer(const channel_t<std::string> & c, size_t cnt)
}
#endif
}
catch (channel_exception e)
catch (channel_exception& e)
{
//MAX_CHANNEL_QUEUE=0,并且先读后写,会触发read_before_write异常
scoped_lock<std::mutex> __lock(cout_mutex);

+ 1
- 1
tutorial/test_async_event.cpp View File

@@ -71,7 +71,7 @@ void test_wait_any()
go[&]() -> future_t<>
{
for (int i = 0; i < _countof(evts); ++i)
for (size_t i = 0; i < _countof(evts); ++i)
{
intptr_t idx = co_await event_t::wait_any(evts);
std::cout << "event " << idx << " signal!" << std::endl;

+ 12
- 12
tutorial/test_async_modern_cb.cpp View File

@@ -84,7 +84,7 @@ auto tostring_async(_Input_t&& value, _Callable_t&& token)
//适配器类型
using _Adapter_t = modern_callback_adapter_t<typename resumef::remove_cvref_t<_Callable_t>, void(std::string)>;
//通过适配器获得兼容_Signature_t类型的真正的回调,以及返回值_Return_t
auto adapter = typename _Adapter_t::traits(std::forward<_Callable_t>(token));
auto adapter = _Adapter_t::traits(std::forward<_Callable_t>(token));

//callback与token未必是同一个变量,甚至未必是同一个类型
std::thread([callback = std::move(std::get<0>(adapter)), value = std::forward<_Input_t>(value)]
@@ -101,7 +101,7 @@ auto tostring_async(_Input_t&& value, _Callable_t&& token)
//或者宏版本写法
#define MODERN_CALLBACK_TRAITS(_Token_value, _Signature_t) \
using _Adapter_t = modern_callback_adapter_t<typename resumef::remove_cvref_t<_Callable_t>, _Signature_t>; \
auto _Adapter_value = typename _Adapter_t::traits(std::forward<_Callable_t>(_Token_value))
auto _Adapter_value = _Adapter_t::traits(std::forward<_Callable_t>(_Token_value))
#define MODERN_CALLBACK_CALL() std::move(std::get<0>(_Adapter_value))
#define MODERN_CALLBACK_RETURN() return std::move(std::get<1>(_Adapter_value)).get()

@@ -139,7 +139,7 @@ struct use_future_callback_base_t

auto get_future() const
{
return _promise.get_future();
return this->_promise.get_future();
}
};

@@ -157,7 +157,7 @@ struct use_future_callback_t<_Promise_traits> : public use_future_callback_base_

void operator()() const
{
_promise.set_value();
this->_promise.set_value();
}
};

@@ -170,9 +170,9 @@ struct use_future_callback_t<_Promise_traits, std::exception_ptr> : public use_f
void operator()(std::exception_ptr eptr) const
{
if (!eptr)
_promise.set_value();
this->_promise.set_value();
else
_promise.set_exception(std::move(eptr));
this->_promise.set_exception(std::move(eptr));
}
};

@@ -185,7 +185,7 @@ struct use_future_callback_t<_Promise_traits, _Result_t> : public use_future_cal
template<typename Arg>
void operator()(Arg && arg) const
{
_promise.set_value(std::forward<Arg>(arg));
this->_promise.set_value(std::forward<Arg>(arg));
}
};

@@ -199,9 +199,9 @@ struct use_future_callback_t<_Promise_traits, std::exception_ptr, _Result_t> : p
void operator()(std::exception_ptr eptr, Arg && arg) const
{
if (!eptr)
_promise.set_value(std::forward<Arg>(arg));
this->_promise.set_value(std::forward<Arg>(arg));
else
_promise.set_exception(std::move(eptr));
this->_promise.set_exception(std::move(eptr));
}
};

@@ -215,7 +215,7 @@ struct use_future_callback_t<_Promise_traits, _Result_t...> : public use_future_
void operator()(Args&&... args) const
{
static_assert(sizeof...(Args) == sizeof...(_Result_t), "");
_promise.set_value(std::make_tuple(std::forward<Args>(args)...));
this->_promise.set_value(std::make_tuple(std::forward<Args>(args)...));
}
};

@@ -230,9 +230,9 @@ struct use_future_callback_t<_Promise_traits, std::exception_ptr, _Result_t...>
{
static_assert(sizeof...(Args) == sizeof...(_Result_t), "");
if (!eptr)
_promise.set_value(std::make_tuple(std::forward<Args>(args)...));
this->_promise.set_value(std::make_tuple(std::forward<Args>(args)...));
else
_promise.set_exception(std::move(eptr));
this->_promise.set_exception(std::move(eptr));
}
};


+ 1
- 1
tutorial/test_async_suspend_always.cpp View File

@@ -9,7 +9,7 @@
using namespace resumef;
future_t<> test_loop_sleep(size_t _N, char * ch)
future_t<> test_loop_sleep(size_t _N, const char * ch)
{
using namespace std::chrono;

+ 2
- 2
tutorial/test_async_switch_scheduler.cpp View File

@@ -24,7 +24,7 @@ void run_in_thread(channel_t<bool>& c_done)
//循环直到sch_in_thread为nullptr
for (;;)
{
auto sch = sch_in_thread.load(std::memory_order::acquire);
auto sch = sch_in_thread.load(std::memory_order_acquire);
if (sch == nullptr)
break;
sch->run_one_batch();
@@ -46,7 +46,7 @@ static void callback_get_long(int64_t val, _Ctype&& cb)
//这种情况下,没有生成 frame-context,因此,并没有promise_type被内嵌在frame-context里
static future_t<int64_t> async_get_long(int64_t val)
{
resumef::awaitable_t<int64_t> awaitable;
awaitable_t<int64_t> awaitable;
callback_get_long(val, [awaitable](int64_t val)
{
awaitable.set_value(val);

+ 3
- 3
tutorial/test_async_when_all.cpp View File

@@ -27,7 +27,7 @@ void test_when_any()
co_await sleep_for(1ms * dt);
std::cout << dt << "@a" << std::endl;
return dt;
co_return dt;
}(),
[]() ->future_t<>
{
@@ -56,7 +56,7 @@ void test_when_any()
co_await sleep_for(1ms * dt);
std::cout << dt << "@" << name << std::endl;
return dt;
co_return dt;
};
std::vector<future_t<int> > v{ my_sleep("g"), my_sleep("h"), my_sleep("i") };
@@ -76,7 +76,7 @@ void test_when_all()
co_await sleep_for(1ms * dt);
std::cout << dt << "@" << name << std::endl;
return dt;
co_return dt;
};
auto my_sleep_v = [](const char * name) -> future_t<>

+ 1
- 2
vs_proj/librf.cpp View File

@@ -3,7 +3,6 @@
#include <experimental/resumable>
#include <experimental/generator>
#include <optional>
#include "async_wrapper.hpp"
extern void resumable_main_yield_return();
extern void resumable_main_timer();
@@ -34,7 +33,7 @@ int main(int argc, const char* argv[])
{
(void)argc;
(void)argv;
resumable_main_switch_scheduler();
resumable_main_layout();
//if (argc > 1)
// resumable_main_benchmark_asio_client(atoi(argv[1]));

+ 1
- 1
vs_proj/librf.vcxproj View File

@@ -23,6 +23,7 @@
<ProjectGuid>{C1D4A6BD-592F-4E48-8178-7C87219BF80E}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>librf</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
@@ -110,7 +111,6 @@
<CLanguageStandard>c11</CLanguageStandard>
<CppLanguageStandard>c++1y</CppLanguageStandard>
<DisableSpecificWarnings>4834</DisableSpecificWarnings>
<EnableModules>true</EnableModules>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>

Loading…
Cancel
Save