39 #ifndef LELY_UTIL_FIBER_HPP_
40 #define LELY_UTIL_FIBER_HPP_
82 operator~(FiberFlag rhs) {
83 return static_cast<FiberFlag
>(~static_cast<int>(rhs));
87 operator&(FiberFlag lhs, FiberFlag rhs) {
88 return static_cast<FiberFlag
>(
static_cast<int>(lhs) &
static_cast<int>(rhs));
92 operator^(FiberFlag lhs, FiberFlag rhs) {
93 return static_cast<FiberFlag>(
static_cast<int>(lhs) ^
static_cast<int>(rhs));
97 operator|(FiberFlag lhs, FiberFlag rhs) {
98 return static_cast<FiberFlag>(
static_cast<int>(lhs) |
static_cast<int>(rhs));
102 operator&=(FiberFlag& lhs, FiberFlag rhs) {
103 return lhs = lhs & rhs;
107 operator^=(FiberFlag& lhs, FiberFlag rhs) {
108 return lhs = lhs ^ rhs;
112 operator|=(FiberFlag& lhs, FiberFlag rhs) {
113 return lhs = lhs | rhs;
123 bool terminated{
false};
125 ::std::exception_ptr eptr{
nullptr};
140 FiberThread() : FiberThread(static_cast<
FiberFlag>(0)) {}
149 explicit FiberThread(FiberFlag flags) {
164 FiberThread(FiberFlag flags,
bool& already) {
167 already = result != 0;
170 FiberThread(
const FiberThread&) =
delete;
171 FiberThread(FiberThread&&) =
delete;
173 FiberThread& operator=(
const FiberThread&) =
delete;
174 FiberThread& operator=(FiberThread&&) =
delete;
183 static detail::FiberData*
186 static detail::FiberData data_;
188 static thread_local detail::FiberData data_;
202 Fiber() noexcept = default;
204 Fiber(const Fiber&) = delete;
211 Fiber(Fiber&& other) noexcept { swap(other); }
216 template <
class F,
class = typename ::std::enable_if<!::std::is_same<
217 typename ::std::decay<F>::type, Fiber>::value>::type>
218 explicit Fiber(F&& f) : Fiber(::std::forward<F>(f), 0) {}
222 Fiber(F&& f, FiberFlag flags) : Fiber(::std::forward<F>(f), flags, 0) {}
226 Fiber(F&& f, ::std::size_t stack_size)
227 : Fiber(::std::forward<F>(f), static_cast<
FiberFlag>(0), stack_size) {}
242 template <
class F,
class = typename ::std::enable_if<compat::is_invocable_r<
243 Fiber, F, Fiber&&>::value>::type>
244 Fiber(F&& f, FiberFlag flags, ::std::size_t stack_size) {
246 &func_<decltype(f)>,
static_cast<void*
>(::std::addressof(f)),
247 static_cast<int>(flags),
sizeof(detail::FiberData), stack_size);
249 auto data = data_(fiber_);
251 new (data) detail::FiberData();
253 *
this = ::std::move(*this).resume();
255 auto eptr = data->eptr;
258 ::std::rethrow_exception(eptr);
262 Fiber& operator=(
const Fiber&) =
delete;
272 operator=(Fiber&& other) noexcept {
293 auto data = data_(fiber_);
295 if (!data->terminated) {
297 *
this = ::std::move(*this).resume();
306 explicit operator bool() const noexcept {
return fiber_ !=
nullptr; }
308 operator fiber_t*() && noexcept {
329 return resume_(Fiber(
fiber_resume(::std::move(*
this))));
348 resume_with(F&& f) && {
352 f = (*
static_cast<F*
>(arg))(::std::move(f));
355 if (!data) data = FiberThread::data_();
356 data->eptr = ::std::current_exception();
358 return static_cast<fiber_t*
>(::std::move(f));
360 auto arg =
static_cast<void*
>(::std::addressof(f));
366 swap(Fiber& other) noexcept {
368 swap(fiber_, other.fiber_);
375 static detail::FiberData*
380 Fiber resume_(Fiber&& f);
393 fiber_unwind() noexcept = default;
395 explicit fiber_unwind(Fiber&& f) noexcept : f_(::std::move(f)) {}
407 using F_ = typename ::std::decay<F>::type;
408 F_ func{::std::forward<F_>(
static_cast<F
>(*
static_cast<F_*
>(arg)))};
415 if (data->eptr) ::std::rethrow_exception(data->eptr);
417 if (!data->unwind) f = func(::std::move(f));
418 }
catch (fiber_unwind& e) {
419 f = ::std::move(e.f_);
421 data->terminated =
true;
422 return ::std::move(f);
427 data->eptr = ::std::current_exception();
437 Fiber::resume_(Fiber&& f) {
439 if (!data) data = FiberThread::data_();
444 auto eptr = data->eptr;
445 data->eptr =
nullptr;
447 if (data->unwind)
throw fiber_unwind(::std::move(f));
448 if (eptr) ::std::rethrow_exception(eptr);
450 return ::std::move(f);
453 #endif // __cpp_exceptions
458 #endif // !LELY_UTIL_FIBER_HPP_