On 30/04/21 10:38 -0400, Patrick Palka via Libstdc++ wrote:
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?
OK, thanks.
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