uvco 0.1
Loading...
Searching...
No Matches
Public Member Functions | Public Attributes | Protected Attributes | List of all members
uvco::PromiseCore< T > Class Template Reference

#include <promise_core.h>

Inheritance diagram for uvco::PromiseCore< T >:
Inheritance graph
[legend]
Collaboration diagram for uvco::PromiseCore< T >:
Collaboration graph
[legend]

Public Member Functions

 PromiseCore ()=default
 
 PromiseCore (const PromiseCore &)=delete
 
 PromiseCore (PromiseCore &&)=delete
 
PromiseCoreoperator= (const PromiseCore &)=delete
 
PromiseCoreoperator= (PromiseCore &&)=delete
 
 PromiseCore (T &&value)
 
virtual void setHandle (std::coroutine_handle<> handle)
 Set the coroutine to be resumed once a result is ready.
 
void resetHandle ()
 
void cancel ()
 
bool willResume ()
 Checks if a coroutine is waiting on a promise belonging to this core.
 
bool ready () const
 Checks if a value is present in the slot.
 
bool stale () const
 
virtual void resume ()
 
virtual ~PromiseCore ()
 
void except (const std::exception_ptr &exc)
 
- Public Member Functions inherited from uvco::RefCounted< PromiseCore< T > >
 RefCounted (const RefCounted &other)=default
 
 RefCounted (RefCounted &&other) noexcept
 
RefCountedoperator= (const RefCounted &other)=default
 
RefCountedoperator= (RefCounted &&other) noexcept
 
virtual ~RefCounted ()=default
 
virtual T * addRef ()
 
virtual void delRef ()
 

Public Attributes

std::optional< std::variant< T, std::exception_ptr > > slot
 The slot contains the result once obtained.
 

Protected Attributes

std::optional< std::coroutine_handle<> > handle_
 
PromiseState state_ = PromiseState::init
 

Additional Inherited Members

- Protected Member Functions inherited from uvco::RefCounted< PromiseCore< T > >
 RefCounted ()=default
 

Detailed Description

template<typename T>
class uvco::PromiseCore< T >

A PromiseCore is shared among copies of promises waiting for the same coroutine. It contains a state, a result (of type T), and potentially a coroutine_handle of the coroutine waiting on it. Only one coroutine may await a promise, this is enforced here.

A PromiseCore is RefCounted; this reduces the overhead of shared_ptr by as much as 50% in Debug mode and 30% in clang Release mode. However, this is only expected to occur in promise-heavy code without involvement of libuv (such as pure channels).

The canonical way would be just using shared_ptr, which is likely fast enough. But we're experimenting, so let's have fun.

Constructor & Destructor Documentation

◆ PromiseCore() [1/4]

template<typename T >
uvco::PromiseCore< T >::PromiseCore ( )
default

◆ PromiseCore() [2/4]

template<typename T >
uvco::PromiseCore< T >::PromiseCore ( const PromiseCore< T > &  )
delete

◆ PromiseCore() [3/4]

template<typename T >
uvco::PromiseCore< T >::PromiseCore ( PromiseCore< T > &&  )
delete

◆ PromiseCore() [4/4]

template<typename T >
uvco::PromiseCore< T >::PromiseCore ( T &&  value)
inlineexplicit
71 : slot{std::move(value)}, state_{PromiseState::finished} {}
PromiseState state_
Definition promise_core.h:188
std::optional< std::variant< T, std::exception_ptr > > slot
The slot contains the result once obtained.
Definition promise_core.h:184

◆ ~PromiseCore()

template<typename T >
virtual uvco::PromiseCore< T >::~PromiseCore ( )
inlinevirtual

Destroys a promise core. Also destroys a coroutine if there is one suspended and has not been resumed yet. In that case, a warning is emitted ("PromiseCore destroyed without ever being resumed").

165 {
167 fmt::print(
168 stderr,
169 "PromiseCore destroyed without ever being resumed ({}, state = {})\n",
170 typeid(T).name(), static_cast<int>(state_));
171 }
172 // This only happens if the awaiting coroutine has never been resumed, but
173 // the last promise provided by it is gone (in turn calling
174 // ~PromiseCore()). Important: we may only destroy a suspended coroutine,
175 // not a finished one.
176 if (handle_) {
177 handle_->destroy();
178 }
179 }
std::optional< std::coroutine_handle<> > handle_
Definition promise_core.h:187

Member Function Documentation

◆ cancel()

template<typename T >
void uvco::PromiseCore< T >::cancel ( )
inline

Cancel a promise. The awaiter, if present, will immediately receive an exception. The coroutine itself will keep running, however. (This may be changed later)

97 {
99 BOOST_ASSERT(!ready());
100 // Fill the slot with an exception, so that the coroutine can be resumed.
101 // Double-check `if` for release builds.
102 if (!slot) {
103 slot = std::make_exception_ptr(
104 UvcoException(UV_ECANCELED, "Promise cancelled"));
105 }
106 resume();
107 }
108 // else: the underlying coroutine has already returned, so there is no need
109 // to cancel it.
110 }
bool ready() const
Checks if a value is present in the slot.
Definition promise_core.h:115
virtual void resume()
Definition promise_core.h:126

◆ except()

template<typename T >
void uvco::PromiseCore< T >::except ( const std::exception_ptr &  exc)
inline
181{ slot = exc; }

◆ operator=() [1/2]

template<typename T >
PromiseCore & uvco::PromiseCore< T >::operator= ( const PromiseCore< T > &  )
delete

◆ operator=() [2/2]

template<typename T >
PromiseCore & uvco::PromiseCore< T >::operator= ( PromiseCore< T > &&  )
delete

◆ ready()

template<typename T >
bool uvco::PromiseCore< T >::ready ( ) const
inline

Checks if a value is present in the slot.

115{ return slot.has_value(); }

◆ resetHandle()

template<typename T >
void uvco::PromiseCore< T >::resetHandle ( )
inline

Reset the handle, so that the coroutine is not resumed anymore. This is required for SelectSet.

84 {
85 BOOST_ASSERT((state_ == PromiseState::waitedOn && handle_) ||
89 handle_.reset();
91 }
92 }

◆ resume()

template<typename T >
virtual void uvco::PromiseCore< T >::resume ( )
inlinevirtual

Resume a suspended coroutine waiting on the associated coroutine by enqueuing it in the global event loop.

A promise core can only be resumed once.

Reimplemented in uvco::MultiPromiseCore< T >.

126 {
127 if (handle_) {
128 BOOST_ASSERT(state_ == PromiseState::waitedOn);
130 auto resume = *handle_;
131 handle_.reset();
133 } else {
134 // This occurs if no co_await has occured until resume. Either the
135 // promise was not co_awaited, or the producing coroutine immediately
136 // returned a value. (await_ready() == true)
137 }
138
139 switch (state_) {
141 // Coroutine returns but nobody has awaited yet. This is fine.
143 break;
145 // Not entirely correct, but the resumed awaiting coroutine is not coming
146 // back to us.
148 break;
150 // state is waitedOn, but no handle is set - that's an error.
151 BOOST_ASSERT_MSG(
152 false,
153 "PromiseCore::resume() called without handle in state waitedOn");
154 break;
156 // Happens in MultiPromiseCore on co_return if the co_awaiter has lost
157 // interest. Harmless if !handle_ (asserted above).
158 break;
159 }
160 }
static void enqueue(std::coroutine_handle<> handle)
Definition loop.cc:73

◆ setHandle()

template<typename T >
virtual void uvco::PromiseCore< T >::setHandle ( std::coroutine_handle<>  handle)
inlinevirtual

Set the coroutine to be resumed once a result is ready.

Reimplemented in uvco::MultiPromiseCore< T >.

74 {
76 throw UvcoException("PromiseCore is already awaited or has finished");
77 }
78 handle_ = handle;
80 }

◆ stale()

template<typename T >
bool uvco::PromiseCore< T >::stale ( ) const
inline

Checks if the coroutine has returned, and the results have been fetched (i.e. after co_return -> co_await).

118 {
119 return state_ == PromiseState::finished && !ready();
120 }

◆ willResume()

template<typename T >
bool uvco::PromiseCore< T >::willResume ( )
inline

Checks if a coroutine is waiting on a promise belonging to this core.

113{ return handle_.has_value(); }

Member Data Documentation

◆ handle_

template<typename T >
std::optional<std::coroutine_handle<> > uvco::PromiseCore< T >::handle_
protected

◆ slot

template<typename T >
std::optional<std::variant<T, std::exception_ptr> > uvco::PromiseCore< T >::slot

The slot contains the result once obtained.

◆ state_

template<typename T >
PromiseState uvco::PromiseCore< T >::state_ = PromiseState::init
protected

The documentation for this class was generated from the following file: