Browse Source

继续完善文档

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

+ 2
- 1
Doxyfile View File

*.vhdl \ *.vhdl \
*.ucf \ *.ucf \
*.qsf \ *.qsf \
*.ice
*.ice \
*.inl
# The RECURSIVE tag can be used to specify whether or not subdirectories should # The RECURSIVE tag can be used to specify whether or not subdirectories should
# be searched for input files as well. # be searched for input files as well.

+ 7
- 0
librf/src/asio_task_1.12.0.inl View File



namespace asio { namespace asio {


/**
* @brief 用于指示asio相关异步函数,返回resumef::future_t<>的类型,从而变成支持 librf 的协程函数。
*/
template <typename Executor = executor> template <typename Executor = executor>
struct rf_task_t struct rf_task_t
{ {
ASIO_CONSTEXPR rf_task_t() {} ASIO_CONSTEXPR rf_task_t() {}
}; };

/**
* @brief 用于指示asio相关异步函数,返回resumef::future_t<>的常量,从而变成支持 librf 的协程函数。
*/
constexpr rf_task_t<> rf_task; constexpr rf_task_t<> rf_task;


namespace librf { namespace librf {

+ 41
- 1
librf/src/awaitable.h View File

#pragma once
#pragma once


namespace resumef namespace resumef
{ {


/**
* @brief awaitable_t<>的公共实现部分,用于减少awaitable_t<>的重复代码。
* @param _Ty 可等待函数(awaitable function)的返回类型。
* @see 参见awaitable_t<>类的说明。
*/
template<class _Ty> template<class _Ty>
struct awaitable_impl_t struct awaitable_impl_t
{ {
awaitable_impl_t& operator = (const awaitable_impl_t&) = default; awaitable_impl_t& operator = (const awaitable_impl_t&) = default;
awaitable_impl_t& operator = (awaitable_impl_t&&) = default; awaitable_impl_t& operator = (awaitable_impl_t&&) = default;


/**
* @brief 发生了异常后,设置异常。
* @attention 与set_value()互斥。调用了set_exception(e)后,不能再调用set_value()。
*/
void set_exception(std::exception_ptr e) const void set_exception(std::exception_ptr e) const
{ {
this->_state->set_exception(std::move(e)); this->_state->set_exception(std::move(e));
this->_state = nullptr; this->_state = nullptr;
} }


/**
* @brief 在协程内部,重新抛出之前设置的异常。
*/
template<class _Exp> template<class _Exp>
void throw_exception(_Exp e) const void throw_exception(_Exp e) const
{ {
set_exception(std::make_exception_ptr(std::move(e))); set_exception(std::make_exception_ptr(std::move(e)));
} }


/**
* @brief 获得与之关联的future_t<>对象,作为可等待函数(awaitable function)的返回值。
*/
future_type get_future() noexcept future_type get_future() noexcept
{ {
return future_type{ this->_state }; return future_type{ this->_state };
} }


/**
* @brief 管理的state_t<>对象。
*/
mutable counted_ptr<state_type> _state = state_future_t::_Alloc_state<state_type>(true); mutable counted_ptr<state_type> _state = state_future_t::_Alloc_state<state_type>(true);
}; };


/**
* @brief 用于包装‘异步函数’为‘可等待函数(awaitable function)’。
* @details 通过返回一个‘可等待对象(awaitor)’,符合C++ coroutines的co_await所需的接口,来达成‘可等待函数(awaitable function)’。\n
* 这是扩展异步函数支持协程的重要手段。\n
* \n
* 典型用法是申明一个 awaitable_t<>局部变量 awaitable,\n
* 在已经获得结果的情况下,直接调用 awaitable.set_value(value)设置返回值,使得可等待函数立即获得结果。\n
* 在不能立即获得结果的情况下,通过在异步的回调lambda里,捕获awaitable局部变量,\n
* 根据异步结果,要么调用 awaitable.set_value(value)设置结果值,要么调用 awaitable.set_exception(e)设置异常。\n
* 在设置值或者异常后,调用可等待函数的协程将得以继续执行。\n
* 此可等待函数通过 awaitable.get_future()返回与之关联的 future_t<>对象,作为协程的可等待对象。\n
* \n
* @param _Ty 可等待函数(awaitable function)的返回类型。\n
* 要求至少支持移动构造和移动赋值。\n
* _Ty 支持特化为 _Ty&,以及 void。
*/
template<class _Ty> template<class _Ty>
struct [[nodiscard]] awaitable_t : public awaitable_impl_t<_Ty> struct [[nodiscard]] awaitable_t : public awaitable_impl_t<_Ty>
{ {
using typename awaitable_impl_t<_Ty>::value_type; using typename awaitable_impl_t<_Ty>::value_type;
using awaitable_impl_t<_Ty>::awaitable_impl_t; using awaitable_impl_t<_Ty>::awaitable_impl_t;


/**
* @brief 设置可等待函数的返回值。
* @details _Ty的void特化版本,则是不带参数的set_value()函数。
* @param value 返回值。必须支持通过value构造出_Ty类型。
* @attention 与set_exception()互斥。调用了set_value(value)后,不能再调用set_exception(e)。
*/
template<class U> template<class U>
void set_value(U&& value) const void set_value(U&& value) const
{ {

+ 1
- 0
librf/src/channel_v2.h View File

/** /**
* @brief 在协程中从channel_t里读取一个数据。 * @brief 在协程中从channel_t里读取一个数据。
* @see 参考read()函数 * @see 参考read()函数
* @return [co_await] value_type
*/ */
read_awaiter operator co_await() const noexcept; read_awaiter operator co_await() const noexcept;



+ 37
- 4
librf/src/counted_ptr.h View File

namespace resumef namespace resumef
{ {
/**
* @brief 专用与state的智能计数指针,通过管理state内嵌的引用计数来管理state的生存期。
*/
template <typename T> template <typename T>
struct counted_ptr struct counted_ptr
{ {
/**
* @brief 构造一个无内容的计数指针。
*/
counted_ptr() noexcept = default; counted_ptr() noexcept = default;
counted_ptr(const counted_ptr& cp) : _p(cp._p)
/**
* @brief 拷贝构造函数。
*/
counted_ptr(const counted_ptr& cp) : _p(cp._p)
{ {
_lock(); _lock();
} }
counted_ptr(T* p) : _p(p)
/**
* @brief 通过裸指针构造一个计数指针。
*/
counted_ptr(T* p) : _p(p)
{ {
_lock(); _lock();
} }
/**
* @brief 移动构造函数。
*/
counted_ptr(counted_ptr&& cp) noexcept counted_ptr(counted_ptr&& cp) noexcept
{ {
std::swap(_p, cp._p); std::swap(_p, cp._p);
} }
counted_ptr& operator=(const counted_ptr& cp)
/**
* @brief 拷贝赋值函数。
*/
counted_ptr& operator=(const counted_ptr& cp)
{ {
if (&cp != this) if (&cp != this)
{ {
return *this; return *this;
} }
/**
* @brief 移动赋值函数。
*/
counted_ptr& operator=(counted_ptr&& cp) noexcept counted_ptr& operator=(counted_ptr&& cp) noexcept
{ {
if (&cp != this) if (&cp != this)
return *this; return *this;
} }
/**
* @brief 析构函数中自动做一个计数减一操作。计数减为0,则删除state对象。
*/
~counted_ptr() ~counted_ptr()
{ {
_unlock(); _unlock();
} }
/**
* @brief 重载指针操作符。
*/
T* operator->() const noexcept T* operator->() const noexcept
{ {
return _p; return _p;
} }
/**
* @brief 获得管理的state指针。
*/
T* get() const noexcept T* get() const noexcept
{ {
return _p; return _p;
} }
/**
* @brief 重置为空指针。
*/
void reset() void reset()
{ {
_unlock(); _unlock();

+ 10
- 0
librf/src/current_scheduler.h View File

scheduler_t* _scheduler; scheduler_t* _scheduler;
}; };
/**
* @brief 获得当前协程绑定的调度器。
* @details 立即返回,没有协程切换和等待。
* @return [co_await] scheduler_t*
*/
inline get_current_scheduler_awaitor get_current_scheduler() inline get_current_scheduler_awaitor get_current_scheduler()
{ {
return {}; return {};
state_base_t* _state; state_base_t* _state;
}; };
/**
* @brief 获得当前协程的跟state指针。
* @details 立即返回,没有协程切换和等待。
* @return [co_await] state_base_t*
*/
inline get_root_state_awaitor get_root_state() inline get_root_state_awaitor get_root_state()
{ {
return {}; return {};

+ 29
- 10
librf/src/exception.inl View File

#pragma once
#pragma once


namespace resumef namespace resumef
{ {


/**
* @brief 错误�。
*/
enum struct error_code enum struct error_code
{ {
none, none,
not_ready, // get_value called when value not available
already_acquired, // attempt to get another future
unlock_more, // unlock ´ÎÊý¶àÓàlock´ÎÊý
read_before_write, // 0ÈÝÁ¿µÄchannel£¬ÏȶÁºóд
timer_canceled, // ¶¨Ê±Æ÷±»ÒâÍâÈ¡Ïû
not_await_lock, // ûÓÐÔÚЭ³ÌÖÐʹÓÃco_awaitµÈ´ýlock½á¹û
not_ready, ///< get_value called when value not available
already_acquired, ///< attempt to get another future
unlock_more, ///< unlock 次数多余lock次数
read_before_write, ///< 0容�的channel,先读�写
timer_canceled, ///< 定时器被�外�消
not_await_lock, ///< 没有在�程中使用co_await等待lock结果


max__ max__
}; };


/**
* @brief 通过错误�获得错误�述字符串。
*/
const char* get_error_string(error_code fe, const char* classname); const char* get_error_string(error_code fe, const char* classname);


/**
* @brief 在�作future_t<>时产生的异常。
*/
const char* get_error_string(error_code fe, const char* classname);
struct future_exception : std::logic_error struct future_exception : std::logic_error
{ {
error_code _error; error_code _error;
} }
}; };


struct lock_exception : std::logic_error
/**
* @brief 错误使用mutex_t时产生的异常。
*/
struct mutex_exception : std::logic_error
{ {
error_code _error; error_code _error;
lock_exception(error_code fe)
: logic_error(get_error_string(fe, "lock_exception"))
mutex_exception(error_code fe)
: logic_error(get_error_string(fe, "mutex_exception"))
, _error(fe) , _error(fe)
{ {
} }
}; };


/**
* @brief 错误使用channel_t时产生的异常(v2版本已���抛此异常了)。
*/
struct channel_exception : std::logic_error struct channel_exception : std::logic_error
{ {
error_code _error; error_code _error;
} }
}; };


/**
* @brief 定时器���消导致的异常。
*/
struct timer_canceled_exception : public std::logic_error struct timer_canceled_exception : public std::logic_error
{ {
error_code _error; error_code _error;

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

namespace resumef namespace resumef
{ {
/**
* @brief 用于resumef协程的返回值。
* @details 由于coroutines的限制,协程的返回值必须明确申明,而不能通过auto推导。\n
* 用在恢复函数(resumeable function)里,支持co_await和co_yield。\n
* 用在可等待函数(awaitable function)里,与awaitable_t<>配套使用。
*/
template<class _Ty> template<class _Ty>
struct [[nodiscard]] future_t struct [[nodiscard]] future_t
{ {

+ 5
- 2
librf/src/generator.h View File

/*
/*
* Modify from <experimental/generator_t.h> * Modify from <experimental/generator_t.h>
* Purpose: Library support of coroutines. generator_t class * Purpose: Library support of coroutines. generator_t class
* http://open-std.org/JTC1/SC22/WG21/docs/papers/2015/p0057r0.pdf * http://open-std.org/JTC1/SC22/WG21/docs/papers/2015/p0057r0.pdf
}; };
#endif //DOXYGEN_SKIP_PROPERTY #endif //DOXYGEN_SKIP_PROPERTY
/**
* @brief 专用于co_yield函数。
*/
template <typename _Ty, typename _Alloc> template <typename _Ty, typename _Alloc>
struct generator_t struct generator_t
{ {
std::cout << " generator_promise::new, return ptr=" << (void*)_Rptr << std::endl; std::cout << " generator_promise::new, return ptr=" << (void*)_Rptr << std::endl;
#endif #endif
//ÔÚ³õʼµØÖ·ÉϹ¹Ôìstate
//在�始地�上构造state
{ {
state_type* st = state_type::_Construct(ptr); state_type* st = state_type::_Construct(ptr);
st->lock(); st->lock();

+ 3
- 3
librf/src/mutex_v2.inl View File

assert(_mutex == nullptr); assert(_mutex == nullptr);
if (_mutex != nullptr) if (_mutex != nullptr)
{ {
throw lock_exception(error_code::not_await_lock);
throw mutex_exception(error_code::not_await_lock);
} }
} }


assert(_mutex == nullptr); assert(_mutex == nullptr);
if (_mutex != nullptr) if (_mutex != nullptr)
{ {
throw lock_exception(error_code::not_await_lock);
throw mutex_exception(error_code::not_await_lock);
} }
} }


assert(_mutex == nullptr); assert(_mutex == nullptr);
if (_mutex != nullptr) if (_mutex != nullptr)
{ {
throw lock_exception(error_code::not_await_lock);
throw mutex_exception(error_code::not_await_lock);
} }
} }



+ 45
- 0
librf/src/sleep.h View File

namespace resumef namespace resumef
{ {
/**
* @brief 协程专用的睡眠功能。
* @details 不能使用操作系统提供的sleep功能,因为会阻塞协程。\n
* 此函数不会阻塞线程,仅仅将当前协程挂起,直到指定时刻。\n
* 其精度,取决与调度器循环的精度,以及std::chrono::system_clock的精度。简而言之,可以认为只要循环够快,精度到100ns。
* @return [co_await] void
* @throw timer_canceled_exception 如果定时器被取消,则抛此异常。
*/
future_t<> sleep_until_(std::chrono::system_clock::time_point tp_, scheduler_t& scheduler_); future_t<> sleep_until_(std::chrono::system_clock::time_point tp_, scheduler_t& scheduler_);
/**
* @brief 协程专用的睡眠功能。
* @see 参考sleep_until_()函数\n
* @return [co_await] void
* @throw timer_canceled_exception 如果定时器被取消,则抛此异常。
*/
inline future_t<> sleep_for_(std::chrono::system_clock::duration dt_, scheduler_t& scheduler_) inline future_t<> sleep_for_(std::chrono::system_clock::duration dt_, scheduler_t& scheduler_)
{ {
return sleep_until_(std::chrono::system_clock::now() + dt_, scheduler_); return sleep_until_(std::chrono::system_clock::now() + dt_, scheduler_);
} }
/**
* @brief 协程专用的睡眠功能。
* @see 参考sleep_until_()函数\n
* @return [co_await] void
* @throw timer_canceled_exception 如果定时器被取消,则抛此异常。
*/
template<class _Rep, class _Period> template<class _Rep, class _Period>
inline future_t<> sleep_for(std::chrono::duration<_Rep, _Period> dt_, scheduler_t& scheduler_) inline future_t<> sleep_for(std::chrono::duration<_Rep, _Period> dt_, scheduler_t& scheduler_)
{ {
return sleep_for_(std::chrono::duration_cast<std::chrono::system_clock::duration>(dt_), scheduler_); return sleep_for_(std::chrono::duration_cast<std::chrono::system_clock::duration>(dt_), scheduler_);
} }
/**
* @brief 协程专用的睡眠功能。
* @see 参考sleep_until_()函数\n
* @return [co_await] void
* @throw timer_canceled_exception 如果定时器被取消,则抛此异常。
*/
template<class _Clock, class _Duration = typename _Clock::duration> template<class _Clock, class _Duration = typename _Clock::duration>
inline future_t<> sleep_until(std::chrono::time_point<_Clock, _Duration> tp_, scheduler_t& scheduler_) inline future_t<> sleep_until(std::chrono::time_point<_Clock, _Duration> tp_, scheduler_t& scheduler_)
{ {
return sleep_until_(std::chrono::time_point_cast<std::chrono::system_clock::duration>(tp_), scheduler_); return sleep_until_(std::chrono::time_point_cast<std::chrono::system_clock::duration>(tp_), scheduler_);
} }
/**
* @brief 协程专用的睡眠功能。
* @see 参考sleep_until_()函数\n
* @return [co_await] void
* @throw timer_canceled_exception 如果定时器被取消,则抛此异常。
*/
template<class _Rep, class _Period> template<class _Rep, class _Period>
inline future_t<> sleep_for(std::chrono::duration<_Rep, _Period> dt_) inline future_t<> sleep_for(std::chrono::duration<_Rep, _Period> dt_)
{ {
scheduler_t* sch = current_scheduler(); scheduler_t* sch = current_scheduler();
co_await sleep_for_(std::chrono::duration_cast<std::chrono::system_clock::duration>(dt_), *sch); co_await sleep_for_(std::chrono::duration_cast<std::chrono::system_clock::duration>(dt_), *sch);
} }
/**
* @brief 协程专用的睡眠功能。
* @see 参考sleep_until_()函数\n
* @return [co_await] void
* @throw timer_canceled_exception 如果定时器被取消,则抛此异常。
*/
template<class _Clock, class _Duration> template<class _Clock, class _Duration>
inline future_t<> sleep_until(std::chrono::time_point<_Clock, _Duration> tp_) inline future_t<> sleep_until(std::chrono::time_point<_Clock, _Duration> tp_)
{ {
co_await sleep_until_(std::chrono::time_point_cast<std::chrono::system_clock::duration>(tp_), *sch); co_await sleep_until_(std::chrono::time_point_cast<std::chrono::system_clock::duration>(tp_), *sch);
} }
/**
* @brief 协程专用的睡眠功能。
* @see 等同调用sleep_for(dt)\n
* @return [co_await] void
* @throw timer_canceled_exception 如果定时器被取消,则抛此异常。
*/
template <class Rep, class Period> template <class Rep, class Period>
inline future_t<> operator co_await(std::chrono::duration<Rep, Period> dt_) inline future_t<> operator co_await(std::chrono::duration<Rep, Period> dt_)
{ {

+ 55
- 1
librf/src/spinlock.h View File

using spinlock = RESUMEF_USE_CUSTOM_SPINLOCK; using spinlock = RESUMEF_USE_CUSTOM_SPINLOCK;
#else #else
/**
* @brief 一个自旋锁实现。
*/
struct spinlock struct spinlock
{ {
static const size_t MAX_ACTIVE_SPIN = 4000; static const size_t MAX_ACTIVE_SPIN = 4000;
std::thread::id owner_thread_id; std::thread::id owner_thread_id;
#endif #endif
/**
* @brief 初始为未加锁。
*/
spinlock() noexcept spinlock() noexcept
{ {
lck = FREE_VALUE; lck = FREE_VALUE;
} }
/**
* @brief 获得锁。会一直阻塞线程直到获得锁。
*/
void lock() noexcept void lock() noexcept
{ {
int val = FREE_VALUE; int val = FREE_VALUE;
#endif #endif
} }
/**
* @brief 尝试获得锁一次。
*/
bool try_lock() noexcept bool try_lock() noexcept
{ {
int val = FREE_VALUE; int val = FREE_VALUE;
return ret; return ret;
} }
/**
* @brief 释放锁。
*/
void unlock() noexcept void unlock() noexcept
{ {
#if _DEBUG #if _DEBUG
} }
#endif //DOXYGEN_SKIP_PROPERTY #endif //DOXYGEN_SKIP_PROPERTY
// class with destructor that unlocks mutexes
/**
* @brief 无死锁的批量枷锁。
* @param _Ty 锁的类型。例如std::mutex,resumef::spinlock,resumef::mutex_t(线程用法)均可。
* @param _Cont 容纳一批锁的容器。
* @param _Assemble 与_Cont配套的锁集合,特化了如何操作_Ty。
*/
template<class _Ty, class _Cont = std::vector<_Ty>, class _Assemble = detail::_LockVectorAssembleT<_Ty, _Cont>> template<class _Ty, class _Cont = std::vector<_Ty>, class _Assemble = detail::_LockVectorAssembleT<_Ty, _Cont>>
class batch_lock_t class batch_lock_t
{ {
public: public:
/**
* @brief 通过锁容器构造,并立刻应用加锁算法。
*/
explicit batch_lock_t(_Cont& locks_) explicit batch_lock_t(_Cont& locks_)
: _LkN(&locks_) : _LkN(&locks_)
, _LA(*_LkN) , _LA(*_LkN)
{ {
detail::scoped_lock_range_lock_impl::_Lock_range(_LA); detail::scoped_lock_range_lock_impl::_Lock_range(_LA);
} }
/**
* @brief 通过锁容器和锁集合构造,并立刻应用加锁算法。
*/
explicit batch_lock_t(_Cont& locks_, _Assemble& la_) explicit batch_lock_t(_Cont& locks_, _Assemble& la_)
: _LkN(&locks_) : _LkN(&locks_)
, _LA(la_) , _LA(la_)
detail::scoped_lock_range_lock_impl::_Lock_range(_LA); detail::scoped_lock_range_lock_impl::_Lock_range(_LA);
} }
/**
* @brief 通过锁容器构造,容器里的锁已经全部获得。
*/
explicit batch_lock_t(std::adopt_lock_t, _Cont& locks_) explicit batch_lock_t(std::adopt_lock_t, _Cont& locks_)
: _LkN(&locks_) : _LkN(&locks_)
, _LA(*_LkN) , _LA(*_LkN)
{ // construct but don't lock { // construct but don't lock
} }
/**
* @brief 通过锁容器和锁集合构造,容器里的锁已经全部获得。
*/
explicit batch_lock_t(std::adopt_lock_t, _Cont& locks_, _Assemble& la_) explicit batch_lock_t(std::adopt_lock_t, _Cont& locks_, _Assemble& la_)
: _LkN(&locks_) : _LkN(&locks_)
, _LA(la_) , _LA(la_)
{ // construct but don't lock { // construct but don't lock
} }
/**
* @brief 析构函数里,释放容器里的锁。
*/
~batch_lock_t() noexcept ~batch_lock_t() noexcept
{ {
if (_LkN != nullptr) if (_LkN != nullptr)
detail::scoped_lock_range_lock_impl::_Unlock_locks(0, (int)_LA.size(), _LA); detail::scoped_lock_range_lock_impl::_Unlock_locks(0, (int)_LA.size(), _LA);
} }
/**
* @brief 手工释放容器里的锁,析构函数里将不再有释放操作。
*/
void unlock() void unlock()
{ {
if (_LkN != nullptr) if (_LkN != nullptr)
} }
} }
/**
* @brief 不支持拷贝构造。
*/
batch_lock_t(const batch_lock_t&) = delete; batch_lock_t(const batch_lock_t&) = delete;
/**
* @brief 不支持拷贝赋值。
*/
batch_lock_t& operator=(const batch_lock_t&) = delete; batch_lock_t& operator=(const batch_lock_t&) = delete;
/**
* @brief 支持移动构造。
*/
batch_lock_t(batch_lock_t&& _Right) batch_lock_t(batch_lock_t&& _Right)
: _LkN(_Right._LkN) : _LkN(_Right._LkN)
, _LA(std::move(_Right._LA)) , _LA(std::move(_Right._LA))
{ {
_Right._LkN = nullptr; _Right._LkN = nullptr;
} }
/**
* @brief 支持移动赋值。
*/
batch_lock_t& operator=(batch_lock_t&& _Right) batch_lock_t& operator=(batch_lock_t&& _Right)
{ {
if (this != &_Right) if (this != &_Right)

+ 12
- 0
librf/src/state.h View File

namespace resumef namespace resumef
{ {
/**
* @brief state基类,state用于在协程的promise和future之间共享数据。
*/
struct state_base_t struct state_base_t
{ {
using _Alloc_char = std::allocator<char>; using _Alloc_char = std::allocator<char>;
} }
}; };
/**
* @brief 专用于generator_t<>的state类。
*/
struct state_generator_t : public state_base_t struct state_generator_t : public state_base_t
{ {
private: private:
static state_generator_t* _Alloc_state(); static state_generator_t* _Alloc_state();
}; };
/**
* @brief 专用于future_t<>的state基类,实现了针对于future_t<>的公共方法等。
*/
struct state_future_t : public state_base_t struct state_future_t : public state_base_t
{ {
enum struct initor_type : uint8_t enum struct initor_type : uint8_t
} }
}; };
/**
* @brief 专用于future_t<>的state类。
*/
template <typename _Ty> template <typename _Ty>
struct state_t final : public state_future_t struct state_t final : public state_future_t
{ {

+ 1
- 0
librf/src/type_traits.inl View File

//is_container_v<T> //is_container_v<T>
//判断是不是一个封闭区间的容器,或者数组。 //判断是不是一个封闭区间的容器,或者数组。
// //
//is_container_of<T, E>
//is_container_of_v<T, E> //is_container_of_v<T, E>
//判断是不是一个封闭区间的容器,或者数组。其元素类型是E。 //判断是不是一个封闭区间的容器,或者数组。其元素类型是E。



+ 4
- 0
librf/src/yield.h View File

} }
}; };


/**
* @fn 将本协程让渡出一次调用。
* @return [co_await] void
*/
inline yield_awaitor yield() inline yield_awaitor yield()
{ {
return {}; return {};

Loading…
Cancel
Save