[PATCH v2 0/2] libstdc++: generators v2
Arsen Arsenović
arsen@aarsen.me
Thu Dec 21 20:01:30 GMT 2023
Hi,
This is v2 of my generators patch. It addresses Jonathans review
comments, but does not add more tests yet :-/
Original series:
https://inbox.sourceware.org/20231118195008.579211-1-arsen@aarsen.me/
Changes since v1:
- Uglify some symbols
- Convert _Is_generator concept to __is_generator CE bool
- Add "libstdc++: add missing include in ranges_util.h" - this can be
pushed separately, really, but I forgot to send it.
Range-diff:
1: feab374887e5 = 1212: c4286af0c70f libstdc++: add missing include in ranges_util.h
2: 010eab271755 ! 1213: fb589641656f libstdc++: implement std::generator
@@ libstdc++-v3/include/std/generator (new)
+#define __glibcxx_want_generator
+#include <bits/version.h>
+
-+#if __cplusplus < 202302L
-+# error "std::generator is a C++23 extension"
-+#endif
-+
+#ifdef __cpp_lib_generator // C++ >= 23 && __glibcxx_coroutine
+#include <new>
+#include <bits/move.h>
@@ libstdc++-v3/include/std/generator (new)
+ {
+ /// _Reference type for a generator whose reference (first argument) and
+ /// value (second argument) types are _Ref and _V.
-+ template<typename _Ref, typename _V>
-+ using _Reference_t = __conditional_t<is_void_v<_V>,
++ template<typename _Ref, typename _Val>
++ using _Reference_t = __conditional_t<is_void_v<_Val>,
+ _Ref&&, _Ref>;
+
+ /// Type yielded by a generator whose _Reference type is _Reference.
@@ libstdc++-v3/include/std/generator (new)
+ const _Reference&>;
+
+ /// _Yield_t * _Reference_t
-+ template<typename _Ref, typename _V>
-+ using _Yield2_t = _Yield_t<_Reference_t<_Ref, _V>>;
-+
-+ template<typename> struct _Is_generator_t : std::false_type {};
-+ template<typename _V, typename _R, typename _A>
-+ struct _Is_generator_t<::std::generator<_V, _R, _A>> : std::true_type {};
-+
-+ template<typename _T>
-+ concept _Is_generator = _Is_generator_t<remove_cvref_t<_T>>::value;
++ template<typename _Ref, typename _Val>
++ using _Yield2_t = _Yield_t<_Reference_t<_Ref, _Val>>;
+
++ template<typename> constexpr bool __is_generator = false;
++ template<typename _Val, typename _Ref, typename _Alloc>
++ constexpr bool __is_generator<std::generator<_Val, _Ref, _Alloc>> = true;
+
+ /// Allocator and value type erased generator promise type.
+ /// \tparam _Yielded The corresponding generators yielded type.
@@ libstdc++-v3/include/std/generator (new)
+ using _Coro_handle = std::coroutine_handle<_Promise_erased>;
+
+ template<typename, typename, typename>
-+ friend struct std::generator;
++ friend class std::generator;
+
+ template<typename _Gen>
+ struct _Recursive_awaiter;
@@ libstdc++-v3/include/std/generator (new)
+ __rn._M_top() = __new;
+
+ // Presume we're the second frame...
-+ auto& __bott = __rest;
++ auto __bott = __rest;
+ if (auto __f = std::get_if<_Frame>(&__rn._M_stack))
+ // But, if we aren't, get the actual bottom. We're only the second
+ // frame if our parent is the bottom frame, i.e. it doesn't have a
@@ libstdc++-v3/include/std/generator (new)
+ struct _Promise_erased<_Yielded>::_Recursive_awaiter
+ {
+ _Gen _M_gen;
-+ static_assert(_Is_generator<_Gen>);
++ static_assert(__is_generator<_Gen>);
+ static_assert(std::same_as<typename _Gen::yielded, _Yielded>);
+
+ _Recursive_awaiter(_Gen __gen) noexcept
@@ libstdc++-v3/include/std/generator (new)
+ requires default_initializable<_Rebound> // _Alloc is non-void
+ { return _M_allocate({}, __sz); }
+
-+ template<typename _NA, typename... _Args>
++ template<typename _Na, typename... _Args>
+ void*
+ operator new(std::size_t __sz,
-+ allocator_arg_t, const _NA& __na,
++ allocator_arg_t, const _Na& __na,
+ const _Args&...)
-+ requires convertible_to<const _NA&, _Alloc>
++ requires convertible_to<const _Na&, _Alloc>
+ {
+ return _M_allocate(static_cast<_Rebound>(static_cast<_Alloc>(__na)),
+ __sz);
+ }
+
-+ template<typename _This, typename _NA, typename... _Args>
++ template<typename _This, typename _Na, typename... _Args>
+ void*
+ operator new(std::size_t __sz,
+ const _This&,
-+ allocator_arg_t, const _NA& __na,
++ allocator_arg_t, const _Na& __na,
+ const _Args&...)
-+ requires convertible_to<const _NA&, _Alloc>
++ requires convertible_to<const _Na&, _Alloc>
+ {
+ return _M_allocate(static_cast<_Rebound>(static_cast<_Alloc>(__na)),
+ __sz);
@@ libstdc++-v3/include/std/generator (new)
+ }
+ }
+
-+ template<typename _NA>
++ template<typename _Na>
+ static void*
-+ _M_allocate(const _NA& __na, std::size_t __csz)
++ _M_allocate(const _Na& __na, std::size_t __csz)
+ {
-+ using _Rebound = typename std::allocator_traits<_NA>
++ using _Rebound = typename std::allocator_traits<_Na>
+ ::template rebind_alloc<_Alloc_block>;
-+ using _Rebound_ATr = typename std::allocator_traits<_NA>
++ using _Rebound_ATr = typename std::allocator_traits<_Na>
+ ::template rebind_traits<_Alloc_block>;
+
+ static_assert(is_pointer_v<typename _Rebound_ATr::pointer>,
@@ libstdc++-v3/include/std/generator (new)
+ return __p;
+ }
+
-+ template<typename _NA, typename... _Args>
++ template<typename _Na, typename... _Args>
+ void*
+ operator new(std::size_t __sz,
-+ allocator_arg_t, const _NA& __na,
++ allocator_arg_t, const _Na& __na,
+ const _Args&...)
+ { return _M_allocate(__na, __sz); }
+
-+ template<typename _This, typename _NA, typename... _Args>
++ template<typename _This, typename _Na, typename... _Args>
+ void*
+ operator new(std::size_t __sz,
+ const _This&,
-+ allocator_arg_t, const _NA& __na,
++ allocator_arg_t, const _Na& __na,
+ const _Args&...)
+ { return _M_allocate(__na, __sz); }
+
@@ libstdc++-v3/include/std/generator (new)
+ }
+ };
+
-+ template<typename _T>
-+ concept _Cv_unqualified_object = is_object_v<_T>
-+ && same_as<_T, remove_cv_t<_T>>;
++ template<typename _Tp>
++ concept _Cv_unqualified_object = is_object_v<_Tp>
++ && same_as<_Tp, remove_cv_t<_Tp>>;
+ } // namespace __gen
+ /// @endcond
+
@@ libstdc++-v3/include/std/generator (new)
+ using difference_type = ptrdiff_t;
+
+ friend bool
-+ operator==(const _Iterator& i, default_sentinel_t) noexcept
-+ { return i._M_coro.done(); }
++ operator==(const _Iterator& __i, default_sentinel_t) noexcept
++ { return __i._M_coro.done(); }
+
+ friend class generator;
+
@@ libstdc++-v3/include/std/generator (new)
+
+#if _GLIBCXX_HOSTED
+ namespace pmr {
-+ template<class R, class V = void>
-+ using generator = std::generator<R, V, polymorphic_allocator<std::byte>>;
++ template<typename _Ref, typename _Val = void>
++ using generator = std::generator<_Ref, _Val, polymorphic_allocator<std::byte>>;
+ }
+#endif // HOSTED
+
Tested libstdc++ on x86_64-pc-linux-gnu.
TIA, have a lovely day.
Arsen Arsenović (2):
libstdc++: add missing include in ranges_util.h
libstdc++: implement std::generator
libstdc++-v3/include/Makefile.am | 2 +
libstdc++-v3/include/Makefile.in | 2 +
libstdc++-v3/include/bits/elements_of.h | 72 ++
libstdc++-v3/include/bits/ranges_util.h | 1 +
libstdc++-v3/include/bits/version.def | 9 +
libstdc++-v3/include/bits/version.h | 11 +
libstdc++-v3/include/precompiled/stdc++.h | 1 +
libstdc++-v3/include/std/generator | 812 ++++++++++++++++++
libstdc++-v3/include/std/ranges | 4 +
.../24_iterators/range_generators/01.cc | 55 ++
.../24_iterators/range_generators/02.cc | 219 +++++
.../24_iterators/range_generators/copy.cc | 97 +++
.../24_iterators/range_generators/except.cc | 97 +++
.../24_iterators/range_generators/subrange.cc | 45 +
.../24_iterators/range_generators/synopsis.cc | 38 +
15 files changed, 1465 insertions(+)
create mode 100644 libstdc++-v3/include/bits/elements_of.h
create mode 100644 libstdc++-v3/include/std/generator
create mode 100644 libstdc++-v3/testsuite/24_iterators/range_generators/01.cc
create mode 100644 libstdc++-v3/testsuite/24_iterators/range_generators/02.cc
create mode 100644 libstdc++-v3/testsuite/24_iterators/range_generators/copy.cc
create mode 100644 libstdc++-v3/testsuite/24_iterators/range_generators/except.cc
create mode 100644 libstdc++-v3/testsuite/24_iterators/range_generators/subrange.cc
create mode 100644 libstdc++-v3/testsuite/24_iterators/range_generators/synopsis.cc
--
2.43.0
More information about the Libstdc++
mailing list