mirror of
https://github.com/gcc-mirror/gcc.git
synced 2026-05-06 14:59:39 +02:00
libstdc++: Add lvalue overload for generator::yield_value
This was approved in Wrocław as LWG 3899. This avoids creating a new coroutine frame to co_yield the elements of an lvalue generator. libstdc++-v3/ChangeLog: * include/std/generator (generator::yield_value): Add overload taking lvalue element_of view, as per LWG 3899. * testsuite/24_iterators/range_generators/lwg3899.cc: New test. Reviewed-by: Tomasz Kamiński <tkaminsk@redhat.com> Reviewed-by: Arsen Arsenović <arsen@aarsen.me>
This commit is contained in:
committed by
Jonathan Wakely
parent
419f40af5c
commit
a4e8d1884e
@@ -153,6 +153,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
noexcept
|
||||
{ return _Recursive_awaiter { std::move(__r.range) }; }
|
||||
|
||||
// _GLIBCXX_RESOLVE_LIB_DEFECTS
|
||||
// 3899. co_yielding elements of an lvalue generator is
|
||||
// unnecessarily inefficient
|
||||
template<typename _R2, typename _V2, typename _A2, typename _U2>
|
||||
requires std::same_as<_Yield2_t<_R2, _V2>, _Yielded>
|
||||
auto
|
||||
yield_value(ranges::elements_of<generator<_R2, _V2, _A2>&, _U2> __r)
|
||||
noexcept
|
||||
{ return _Recursive_awaiter { std::move(__r.range) }; }
|
||||
|
||||
template<ranges::input_range _R, typename _Alloc>
|
||||
requires convertible_to<ranges::range_reference_t<_R>, _Yielded>
|
||||
auto
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
// { dg-do run { target c++23 } }
|
||||
|
||||
// LWG 3899.
|
||||
// co_yielding elements of an lvalue generator is unnecessarily inefficient
|
||||
|
||||
#include <generator>
|
||||
#include <memory_resource>
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
struct memory_resource : std::pmr::memory_resource
|
||||
{
|
||||
std::size_t count = 0;
|
||||
|
||||
void* do_allocate(std::size_t n, std::size_t a) override
|
||||
{
|
||||
count += n;
|
||||
return std::pmr::new_delete_resource()->allocate(n, a);
|
||||
}
|
||||
|
||||
void do_deallocate(void* p, std::size_t n, std::size_t a) override
|
||||
{
|
||||
return std::pmr::new_delete_resource()->deallocate(p, n, a);
|
||||
}
|
||||
|
||||
bool do_is_equal(const std::pmr::memory_resource& mr) const noexcept override
|
||||
{ return this == &mr; }
|
||||
};
|
||||
|
||||
std::pmr::generator<int>
|
||||
f(std::allocator_arg_t, std::pmr::polymorphic_allocator<>, int init)
|
||||
{
|
||||
co_yield init + 0;
|
||||
co_yield init + 1;
|
||||
}
|
||||
|
||||
std::pmr::generator<int>
|
||||
g(std::allocator_arg_t, std::pmr::polymorphic_allocator<> alloc)
|
||||
{
|
||||
auto gen = f(std::allocator_arg, alloc, 0);
|
||||
auto gen2 = f(std::allocator_arg, alloc, 2);
|
||||
co_yield std::ranges::elements_of(std::move(gen), alloc);
|
||||
co_yield std::ranges::elements_of(gen2, alloc);
|
||||
}
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
std::size_t counts[4];
|
||||
memory_resource mr;
|
||||
for (auto d : g(std::allocator_arg , &mr))
|
||||
counts[d] = mr.count;
|
||||
VERIFY(counts[0] != 0);
|
||||
// No allocations after the first one:
|
||||
VERIFY(counts[1] == counts[0]);
|
||||
VERIFY(counts[2] == counts[0]);
|
||||
VERIFY(counts[3] == counts[0]);
|
||||
}
|
||||
Reference in New Issue
Block a user