This implements the wording changes of "join_view should join all views of ranges".
Tested on x86_64-pc-linux-gnu, does this look OK for trunk? libstdc++-v3/ChangeLog: * include/std/ranges (__detail::__non_propating_cache): Define as per P2328. (join_view): Remove constraints on the value and reference types of the wrapped iterator type as per P2328. (join_view::_Iterator::_M_satisfy): Adjust as per P2328. (join_view::_Iterator::operator++): Likewise. (join_view::_M_inner): Use __non_propating_cache as per P2328. Remove now-redundant use of __maybe_present_t. * testsuite/std/ranges/adaptors/join.cc (test10): New test. --- libstdc++-v3/include/std/ranges | 70 ++++++++++++++++--- .../testsuite/std/ranges/adaptors/join.cc | 12 ++++ 2 files changed, 71 insertions(+), 11 deletions(-) diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges index 4be643baeaa..b43f9b337a4 100644 --- a/libstdc++-v3/include/std/ranges +++ b/libstdc++-v3/include/std/ranges @@ -2258,10 +2258,61 @@ namespace views::__adaptor inline constexpr _DropWhile drop_while; } // namespace views + namespace __detail + { + template<typename _Tp> + struct __non_propagating_cache + { + // When _Tp is not an object type (e.g. is a reference type), we make + // __non_propagating_cache<_Tp> empty rather than an invalid type so + // that users can easily conditionally declare data members with this + // type (such as join_view::_M_inner). + }; + + template<typename _Tp> + requires is_object_v<_Tp> + struct __non_propagating_cache<_Tp> : private optional<_Tp> + { + __non_propagating_cache() = default; + + constexpr + __non_propagating_cache(const __non_propagating_cache&) noexcept + { } + + constexpr + __non_propagating_cache(__non_propagating_cache&& __other) noexcept + { __other.reset(); } + + constexpr __non_propagating_cache& + operator=(const __non_propagating_cache& __other) noexcept + { + if (std::__addressof(__other) != this) + this->reset(); + return *this; + } + + constexpr __non_propagating_cache& + operator=(__non_propagating_cache&& __other) noexcept + { + this->reset(); + __other.reset(); + return *this; + } + + using optional<_Tp>::operator*; + + template<typename _Iter> + _Tp& + _M_emplace_deref(const _Iter& __i) + { + this->reset(); + return this->emplace(*__i); + } + }; + } + template<input_range _Vp> requires view<_Vp> && input_range<range_reference_t<_Vp>> - && (is_reference_v<range_reference_t<_Vp>> - || view<range_value_t<_Vp>>) class join_view : public view_interface<join_view<_Vp>> { private: @@ -2327,17 +2378,16 @@ namespace views::__adaptor constexpr void _M_satisfy() { - auto __update_inner = [this] (range_reference_t<_Base> __x) -> auto& - { + auto __update_inner = [this] (const iterator_t<_Base>& __x) -> auto&& { if constexpr (_S_ref_is_glvalue) - return __x; + return *__x; else - return (_M_parent->_M_inner = views::all(std::move(__x))); + return _M_parent->_M_inner._M_emplace_deref(__x); }; for (; _M_outer != ranges::end(_M_parent->_M_base); ++_M_outer) { - auto& __inner = __update_inner(*_M_outer); + auto&& __inner = __update_inner(_M_outer); _M_inner = ranges::begin(__inner); if (_M_inner != ranges::end(__inner)) return; @@ -2413,7 +2463,7 @@ namespace views::__adaptor if constexpr (_S_ref_is_glvalue) return *_M_outer; else - return _M_parent->_M_inner; + return *_M_parent->_M_inner; }(); if (++_M_inner == ranges::end(__inner_range)) { @@ -2524,10 +2574,8 @@ namespace views::__adaptor friend _Sentinel<!_Const>; }; - // XXX: _M_inner is "present only when !is_reference_v<_InnerRange>" [[no_unique_address]] - __detail::__maybe_present_t<!is_reference_v<_InnerRange>, - views::all_t<_InnerRange>> _M_inner; + __detail::__non_propagating_cache<remove_cv_t<_InnerRange>> _M_inner; _Vp _M_base = _Vp(); public: diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/join.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/join.cc index fb06a7698af..6890b105eab 100644 --- a/libstdc++-v3/testsuite/std/ranges/adaptors/join.cc +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/join.cc @@ -160,6 +160,17 @@ test09() static_assert(!requires { 0 | join; }); } +void +test10() +{ +// Verify P2328 changes. + int r[] = {1, 2, 3}; + auto v = r + | views::transform([] (int n) { return std::vector{{n, -n}}; }) + | views::join; + VERIFY( ranges::equal(v, (int[]){1, -1, 2, -2, 3, -3}) ); +} + int main() { @@ -172,4 +183,5 @@ main() test07(); test08(); test09(); + test10(); } -- 2.31.1.362.g311531c9de