Skip to content

Instantly share code, notes, and snippets.

@CoffeeVampir3
Created October 26, 2023 13:28
Show Gist options
  • Select an option

  • Save CoffeeVampir3/e5ea60505f2d5c39cc7e5ce84c449d90 to your computer and use it in GitHub Desktop.

Select an option

Save CoffeeVampir3/e5ea60505f2d5c39cc7e5ce84c449d90 to your computer and use it in GitHub Desktop.
GeneratorEx
#pragma once
#include <coroutine>
namespace CoTools
{
template<typename T> class TWeakPromise;
template<typename T>
struct [[nodiscard]] TWeakGenerator
{
using promise_type = TWeakPromise<T>;
friend promise_type;
explicit TWeakGenerator(std::coroutine_handle<promise_type> Handle) noexcept : Handle(Handle) { }
~TWeakGenerator()
{
if (Handle)
Handle.destroy();
}
TWeakGenerator(const TWeakGenerator&) = delete;
TWeakGenerator& operator=(const TWeakGenerator&) = delete;
TWeakGenerator& operator=(TWeakGenerator&&) = delete;
explicit operator bool() const noexcept {
Handle();
return Handle && !Handle.done();
}
T& operator()() const
{
checkf(Handle && Handle.promise().PromiseValue,
TEXT("Attempted to use a TWeakGenerator but the handle is not valid."));
return *static_cast<T*>(Handle.promise().PromiseValue);
}
private:
std::coroutine_handle<promise_type> Handle;
};
class [[nodiscard]] FWeakPromise
{
public:
FWeakPromise() = default;
UE_NONCOPYABLE(FWeakPromise);
std::suspend_never initial_suspend() noexcept { return {}; }
std::suspend_always final_suspend() noexcept { return {}; }
void return_void() noexcept { PromiseValue = nullptr; }
void unhandled_exception();
protected:
void* PromiseValue = nullptr;
};
template<typename T>
class [[nodiscard]] TWeakPromise : public FWeakPromise
{
friend TWeakGenerator<T>;
using HandleType = std::coroutine_handle<TWeakPromise>;
public:
TWeakGenerator<T> get_return_object() noexcept
{
return TWeakGenerator<T>(HandleType::from_promise(*this));
}
std::suspend_always yield_value(std::remove_reference_t<T>& Value) noexcept
{
PromiseValue = std::addressof(Value);
return {};
}
std::suspend_always yield_value(std::remove_reference_t<T>&& Value) noexcept
{
PromiseValue = std::addressof(Value);
return {};
}
};
}
#pragma once
#include <coroutine>
namespace CoTools
{
template<typename T>
struct [[nodiscard]] TValueGenerator {
struct promise_type;
using HandleType = std::coroutine_handle<promise_type>;
struct promise_type {
T PromiseValue;
TValueGenerator get_return_object() {
return TValueGenerator(HandleType::from_promise(*this));
}
std::suspend_never initial_suspend() { return {}; }
std::suspend_always final_suspend() noexcept { return {}; }
void unhandled_exception() {}
template<std::convertible_to<T> From>
std::suspend_always yield_value(From &&from) {
PromiseValue = std::forward<From>(from);
return {};
}
void return_void() {}
};
HandleType GeneratorHandle;
TValueGenerator(HandleType Handle) : GeneratorHandle(Handle) {}
TValueGenerator(const TValueGenerator&) = delete;
~TValueGenerator() {GeneratorHandle.destroy();}
explicit operator bool() const noexcept {
GeneratorHandle();
return !GeneratorHandle.done();
}
T operator()() const {
return std::move(GeneratorHandle.promise().PromiseValue);
}
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment