mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-03 21:41:26 +12:00
Introduce coroutine support (util/coro.hpp)
Implement coroutine types `lazy` and `generator` in stx namespace. Implement fs::list_dir_recursively.
This commit is contained in:
parent
d6420b8803
commit
6b40d69a8f
4 changed files with 409 additions and 1 deletions
|
@ -9,6 +9,7 @@
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
#include "util/asm.hpp"
|
#include "util/asm.hpp"
|
||||||
|
#include "util/coro.hpp"
|
||||||
|
|
||||||
using namespace std::literals::string_literals;
|
using namespace std::literals::string_literals;
|
||||||
|
|
||||||
|
@ -2039,6 +2040,30 @@ bool fs::pending_file::commit(bool overwrite)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stx::generator<fs::dir_entry&> fs::list_dir_recursively(std::string path)
|
||||||
|
{
|
||||||
|
for (auto& entry : fs::dir(path))
|
||||||
|
{
|
||||||
|
if (entry.name == "." || entry.name == "..")
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string new_path = path_append(path, entry.name);
|
||||||
|
|
||||||
|
if (entry.is_directory)
|
||||||
|
{
|
||||||
|
for (auto& nested : fs::list_dir_recursively(new_path))
|
||||||
|
{
|
||||||
|
co_yield nested;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
entry.name = std::move(new_path);
|
||||||
|
co_yield entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
void fmt_class_string<fs::seek_mode>::format(std::string& out, u64 arg)
|
void fmt_class_string<fs::seek_mode>::format(std::string& out, u64 arg)
|
||||||
{
|
{
|
||||||
|
|
|
@ -804,4 +804,6 @@ namespace fs
|
||||||
}
|
}
|
||||||
|
|
||||||
file make_gather(std::vector<file>);
|
file make_gather(std::vector<file>);
|
||||||
|
|
||||||
|
stx::generator<dir_entry&> list_dir_recursively(std::string path);
|
||||||
}
|
}
|
||||||
|
|
375
rpcs3/util/coro.hpp
Normal file
375
rpcs3/util/coro.hpp
Normal file
|
@ -0,0 +1,375 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if __has_include(<coroutine>)
|
||||||
|
#if defined(__clang__) && !defined(__cpp_impl_coroutine)
|
||||||
|
#define __cpp_impl_coroutine 123
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <coroutine>
|
||||||
|
|
||||||
|
#if defined(__clang__) && (__cpp_impl_coroutine == 123)
|
||||||
|
namespace std::experimental
|
||||||
|
{
|
||||||
|
using ::std::coroutine_traits;
|
||||||
|
using ::std::coroutine_handle;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#elif __has_include(<experimental/coroutine>)
|
||||||
|
#include <experimental/coroutine>
|
||||||
|
|
||||||
|
namespace std
|
||||||
|
{
|
||||||
|
using experimental::coroutine_traits;
|
||||||
|
using experimental::coroutine_handle;
|
||||||
|
using experimental::noop_coroutine_handle;
|
||||||
|
using experimental::suspend_always;
|
||||||
|
using experimental::suspend_never;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <iterator>
|
||||||
|
|
||||||
|
namespace stx
|
||||||
|
{
|
||||||
|
template <typename T>
|
||||||
|
struct lazy;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct generator;
|
||||||
|
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
struct lazy_promise_base
|
||||||
|
{
|
||||||
|
struct final_suspend_t
|
||||||
|
{
|
||||||
|
constexpr bool await_ready() const noexcept { return false; }
|
||||||
|
|
||||||
|
template <typename P>
|
||||||
|
std::coroutine_handle<> await_suspend(std::coroutine_handle<P> h) noexcept
|
||||||
|
{
|
||||||
|
return h.promise().m_handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
void await_resume() noexcept {}
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr lazy_promise_base() noexcept = default;
|
||||||
|
lazy_promise_base(const lazy_promise_base&) = delete;
|
||||||
|
lazy_promise_base& operator=(const lazy_promise_base&) = delete;
|
||||||
|
std::suspend_always initial_suspend() { return {}; }
|
||||||
|
final_suspend_t final_suspend() noexcept { return {}; }
|
||||||
|
void unhandled_exception() {}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::coroutine_handle<> m_handle{};
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct lazy_promise final : lazy_promise_base
|
||||||
|
{
|
||||||
|
constexpr lazy_promise() noexcept = default;
|
||||||
|
|
||||||
|
lazy<T> get_return_object() noexcept;
|
||||||
|
|
||||||
|
template <typename U>
|
||||||
|
void return_value(U&& value)
|
||||||
|
{
|
||||||
|
m_value = std::forward<U>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
T& result() &
|
||||||
|
{
|
||||||
|
return m_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
T&& result() &&
|
||||||
|
{
|
||||||
|
return m_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
T m_value{};
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct lazy_promise<T&> final : lazy_promise_base
|
||||||
|
{
|
||||||
|
constexpr lazy_promise() noexcept = default;
|
||||||
|
|
||||||
|
lazy<T&> get_return_object() noexcept;
|
||||||
|
|
||||||
|
void return_value(T& value) noexcept
|
||||||
|
{
|
||||||
|
m_value = std::addressof(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
T& result()
|
||||||
|
{
|
||||||
|
return *m_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
T* m_value{};
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct lazy_promise<void> final : lazy_promise_base
|
||||||
|
{
|
||||||
|
constexpr lazy_promise() noexcept = default;
|
||||||
|
lazy<void> get_return_object() noexcept;
|
||||||
|
void return_void() noexcept {}
|
||||||
|
void result() {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T = void>
|
||||||
|
struct [[nodiscard]] lazy
|
||||||
|
{
|
||||||
|
using promise_type = detail::lazy_promise<T>;
|
||||||
|
using value_type = T;
|
||||||
|
|
||||||
|
struct awaitable_base
|
||||||
|
{
|
||||||
|
std::coroutine_handle<promise_type> coro;
|
||||||
|
|
||||||
|
bool await_ready() const noexcept
|
||||||
|
{
|
||||||
|
return !coro || coro.done();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::coroutine_handle<> await_suspend(std::coroutine_handle<> h) noexcept
|
||||||
|
{
|
||||||
|
coro.promise().m_handle = h;
|
||||||
|
return coro;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
lazy(const lazy&) = delete;
|
||||||
|
|
||||||
|
lazy(lazy&& rhs) noexcept
|
||||||
|
: m_handle(rhs.m_handle)
|
||||||
|
{
|
||||||
|
rhs.m_handle = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
lazy& operator=(const lazy&) = delete;
|
||||||
|
|
||||||
|
~lazy()
|
||||||
|
{
|
||||||
|
if (m_handle)
|
||||||
|
{
|
||||||
|
m_handle.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_ready() const noexcept
|
||||||
|
{
|
||||||
|
return !m_handle || m_handle.done();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto operator co_await() const & noexcept
|
||||||
|
{
|
||||||
|
struct awaitable : awaitable_base
|
||||||
|
{
|
||||||
|
using awaitable_base::awaitable_base;
|
||||||
|
|
||||||
|
decltype(auto) await_resume()
|
||||||
|
{
|
||||||
|
return this->m_handle.promise().result();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return awaitable{m_handle};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto operator co_await() const && noexcept
|
||||||
|
{
|
||||||
|
struct awaitable : awaitable_base
|
||||||
|
{
|
||||||
|
using awaitable_base::awaitable_base;
|
||||||
|
|
||||||
|
decltype(auto) await_resume()
|
||||||
|
{
|
||||||
|
return std::move(this->m_handle.promise()).result();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return awaitable{m_handle};
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend promise_type;
|
||||||
|
|
||||||
|
explicit constexpr lazy(std::coroutine_handle<promise_type> h) noexcept
|
||||||
|
: m_handle(h)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::coroutine_handle<promise_type> m_handle;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline lazy<T> detail::lazy_promise<T>::get_return_object() noexcept
|
||||||
|
{
|
||||||
|
return lazy<T>{std::coroutine_handle<lazy_promise>::from_promise(*this)};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline lazy<T&> detail::lazy_promise<T&>::get_return_object() noexcept
|
||||||
|
{
|
||||||
|
return lazy<T&>{std::coroutine_handle<lazy_promise>::from_promise(*this)};
|
||||||
|
}
|
||||||
|
|
||||||
|
inline lazy<void> detail::lazy_promise<void>::get_return_object() noexcept
|
||||||
|
{
|
||||||
|
return lazy<void>{std::coroutine_handle<lazy_promise>::from_promise(*this)};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
template <typename T>
|
||||||
|
struct generator_promise
|
||||||
|
{
|
||||||
|
using value_type = std::remove_reference_t<T>;
|
||||||
|
using reference_type = std::conditional_t<std::is_reference_v<T>, T, T&>;
|
||||||
|
|
||||||
|
generator_promise() = default;
|
||||||
|
|
||||||
|
generator<T> get_return_object() noexcept;
|
||||||
|
|
||||||
|
constexpr std::suspend_always initial_suspend() const noexcept { return {}; }
|
||||||
|
constexpr std::suspend_always final_suspend() const noexcept { return {}; }
|
||||||
|
void unhandled_exception() {}
|
||||||
|
|
||||||
|
std::suspend_always yield_value(std::remove_reference_t<T>& value) noexcept
|
||||||
|
{
|
||||||
|
m_ptr = std::addressof(value);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::suspend_always yield_value(std::remove_reference_t<T>&& value) noexcept
|
||||||
|
{
|
||||||
|
m_ptr = std::addressof(value);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void return_void() {}
|
||||||
|
|
||||||
|
reference_type value() const noexcept
|
||||||
|
{
|
||||||
|
return static_cast<reference_type>(*m_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U>
|
||||||
|
std::suspend_never await_transform(U&& value) = delete;
|
||||||
|
|
||||||
|
private:
|
||||||
|
value_type* m_ptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct generator_end
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct generator_iterator
|
||||||
|
{
|
||||||
|
using iterator_category = std::input_iterator_tag;
|
||||||
|
using value_type = typename generator_promise<T>::value_type;
|
||||||
|
using reference = typename generator_promise<T>::reference_type;
|
||||||
|
|
||||||
|
constexpr generator_iterator() noexcept = default;
|
||||||
|
|
||||||
|
explicit constexpr generator_iterator(std::coroutine_handle<generator_promise<T>> coro) noexcept
|
||||||
|
: m_coro(coro)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(generator_end) const noexcept
|
||||||
|
{
|
||||||
|
return !m_coro || m_coro.done();
|
||||||
|
}
|
||||||
|
|
||||||
|
generator_iterator& operator++()
|
||||||
|
{
|
||||||
|
m_coro.resume();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator++(int)
|
||||||
|
{
|
||||||
|
m_coro.resume();
|
||||||
|
}
|
||||||
|
|
||||||
|
reference operator*() const noexcept
|
||||||
|
{
|
||||||
|
return m_coro.promise().value();
|
||||||
|
}
|
||||||
|
|
||||||
|
value_type* operator->() const noexcept
|
||||||
|
{
|
||||||
|
return std::addressof(operator*());
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::coroutine_handle<generator_promise<T>> m_coro;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct [[nodiscard]] generator
|
||||||
|
{
|
||||||
|
using promise_type = detail::generator_promise<T>;
|
||||||
|
using iterator = detail::generator_iterator<T>;
|
||||||
|
|
||||||
|
generator(const generator&) = delete;
|
||||||
|
|
||||||
|
generator(generator&& rhs) noexcept
|
||||||
|
: m_handle(rhs.m_handle)
|
||||||
|
{
|
||||||
|
rhs.m_handle = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
generator& operator=(const generator&) = delete;
|
||||||
|
|
||||||
|
~generator()
|
||||||
|
{
|
||||||
|
if (m_handle)
|
||||||
|
{
|
||||||
|
m_handle.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator begin()
|
||||||
|
{
|
||||||
|
if (m_handle)
|
||||||
|
{
|
||||||
|
m_handle.resume();
|
||||||
|
}
|
||||||
|
|
||||||
|
return iterator{m_handle};
|
||||||
|
}
|
||||||
|
|
||||||
|
detail::generator_end end() noexcept
|
||||||
|
{
|
||||||
|
return detail::generator_end{};
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend promise_type;
|
||||||
|
|
||||||
|
explicit constexpr generator(std::coroutine_handle<promise_type> h) noexcept
|
||||||
|
: m_handle(h)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::coroutine_handle<promise_type> m_handle;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
generator<T> detail::generator_promise<T>::get_return_object() noexcept
|
||||||
|
{
|
||||||
|
return generator<T>{std::coroutine_handle<generator_promise<T>>::from_promise(*this)};
|
||||||
|
}
|
||||||
|
}
|
|
@ -131,6 +131,12 @@ namespace stx
|
||||||
{
|
{
|
||||||
template <typename T, bool Se, usz Align>
|
template <typename T, bool Se, usz Align>
|
||||||
class se_t;
|
class se_t;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct lazy;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct generator;
|
||||||
}
|
}
|
||||||
|
|
||||||
using stx::se_t;
|
using stx::se_t;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue