-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
test std::generator(co_yield elements_of)/std::generator(for generato…
…r)/oeo::generator(no coroutine stack) performance at different depths
- Loading branch information
Showing
4 changed files
with
528 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
// 此实现来自群友@OEOTYAN | ||
#ifndef __GENERATOR_HPP__ | ||
#define __GENERATOR_HPP__ | ||
#pragma once | ||
|
||
#include <concepts> | ||
#include <coroutine> | ||
#include <cstddef> | ||
#include <exception> | ||
#include <type_traits> | ||
#include <utility> | ||
#include <iterator> | ||
|
||
namespace oeo { | ||
|
||
template <class T> | ||
struct generator { | ||
using value = std::remove_cvref_t<T>; | ||
using reference = T&&; | ||
using yielded = reference; | ||
|
||
|
||
struct promise_type { | ||
std::add_pointer_t<yielded> ptr; | ||
std::exception_ptr exception; | ||
|
||
generator get_return_object() noexcept { return generator{*this}; } | ||
|
||
std::suspend_always initial_suspend() noexcept { return {}; } | ||
|
||
std::suspend_always final_suspend() noexcept { return {}; } | ||
|
||
void unhandled_exception() noexcept { exception = std::current_exception(); } | ||
|
||
void rethrow() { | ||
if (exception) { | ||
std::rethrow_exception(exception); | ||
} | ||
} | ||
std::suspend_always yield_value(yielded val) noexcept { | ||
ptr = std::addressof(val); | ||
return {}; | ||
} | ||
auto yield_value(std::remove_reference_t<yielded> const& lval) | ||
requires std::is_rvalue_reference_v<yielded> && | ||
std::constructible_from<std::remove_cvref_t<yielded>, std::remove_reference_t<yielded> const&> | ||
{ | ||
struct yield_copied { | ||
std::remove_cvref_t<yielded> storage; | ||
constexpr yield_copied(std::remove_reference_t<yielded> const& v) : storage(v) {} | ||
constexpr bool await_ready() const noexcept { return false; } | ||
constexpr void await_suspend(std::coroutine_handle<promise_type> h) noexcept { | ||
h.promise().ptr = std::addressof(storage); | ||
} | ||
constexpr void await_resume() const noexcept {} | ||
}; | ||
return yield_copied{lval}; | ||
} | ||
void return_void() noexcept {} | ||
|
||
template <class U> | ||
U&& await_transform(U&&) = delete; | ||
}; | ||
|
||
struct iterator { | ||
using iterator_category = std::input_iterator_tag; | ||
using difference_type = ptrdiff_t; | ||
using value_type = generator::value; | ||
using reference = generator::reference; | ||
using pointer = std::add_pointer_t<yielded>; | ||
|
||
std::coroutine_handle<promise_type> handle = nullptr; | ||
|
||
iterator() = default; | ||
explicit iterator(std::coroutine_handle<promise_type> handle) noexcept : handle(handle) {} | ||
|
||
iterator& operator++() { | ||
handle.resume(); | ||
if (handle.done()) { | ||
std::exchange(handle, nullptr).promise().rethrow(); | ||
} | ||
|
||
return *this; | ||
} | ||
|
||
void operator++(int) { ++*this; } | ||
|
||
[[nodiscard]] bool operator==(iterator const& other) const noexcept { return handle == other.handle; } | ||
|
||
[[nodiscard]] bool operator!=(iterator const& other) const noexcept { return !(*this == other); } | ||
|
||
[[nodiscard]] reference operator*() const noexcept { return static_cast<reference>(*handle.promise().ptr); } | ||
|
||
[[nodiscard]] pointer operator->() const noexcept { return handle.promise().ptr; } | ||
}; | ||
[[nodiscard]] iterator begin() { | ||
if (handle) { | ||
handle.resume(); | ||
if (handle.done()) { | ||
handle.promise().rethrow(); | ||
return {}; | ||
} | ||
} | ||
return iterator{handle}; | ||
} | ||
|
||
[[nodiscard]] iterator end() noexcept { return {}; } | ||
|
||
constexpr generator(generator&& other) noexcept : handle(std::exchange(other.handle, nullptr)) {} | ||
|
||
constexpr ~generator() { | ||
if (handle) { | ||
handle.destroy(); | ||
} | ||
} | ||
constexpr generator() = default; | ||
|
||
generator& operator=(generator&& other) noexcept { | ||
std::swap(other.handle, handle); | ||
return *this; | ||
} | ||
|
||
private: | ||
constexpr explicit generator(promise_type& promise) noexcept | ||
: handle(std::coroutine_handle<promise_type>::from_promise(promise)) {} | ||
|
||
std::coroutine_handle<promise_type> handle = nullptr; | ||
}; | ||
} // namespace oeo | ||
|
||
#endif /* __GENERATOR_HPP__ */ |
Oops, something went wrong.