//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 // UNSUPPORTED: !c++experimental // std::views::join #include #include #include #include "types.h" struct MoveOnlyOuter : SimpleForwardCommonOuter { using SimpleForwardCommonOuter::SimpleForwardCommonOuter; constexpr MoveOnlyOuter(MoveOnlyOuter&&) = default; constexpr MoveOnlyOuter(const MoveOnlyOuter&) = delete; constexpr MoveOnlyOuter& operator=(MoveOnlyOuter&&) = default; constexpr MoveOnlyOuter& operator=(const MoveOnlyOuter&) = delete; }; struct Foo { int i; constexpr Foo(int ii) : i(ii) {} }; template concept CanBePiped = requires(View&& view, T&& t) { { std::forward(view) | std::forward(t) }; }; constexpr bool test() { int buffer1[3] = {1, 2, 3}; int buffer2[2] = {4, 5}; int buffer3[4] = {6, 7, 8, 9}; Foo nested[2][3][3] = {{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}, {{10, 11, 12}, {13, 14, 15}, {16, 17, 18}}}; { // Test `views::join(v)` ForwardCommonInner inners[3] = {buffer1, buffer2, buffer3}; using Result = std::ranges::join_view>; std::same_as decltype(auto) v = std::views::join(inners); assert(std::ranges::next(v.begin(), 9) == v.end()); assert(&(*v.begin()) == buffer1); } { // Test `views::join(move-only-view)` ForwardCommonInner inners[3] = {buffer1, buffer2, buffer3}; using Result = std::ranges::join_view; std::same_as decltype(auto) v = std::views::join(MoveOnlyOuter{inners}); assert(std::ranges::next(v.begin(), 9) == v.end()); assert(&(*v.begin()) == buffer1); static_assert(std::invocable); static_assert(!std::invocable); } { // LWG3474 Nesting `join_views` is broken because of CTAD // views::join(join_view) should join the view instead of calling copy constructor auto jv = std::views::join(nested); ASSERT_SAME_TYPE(std::ranges::range_reference_t, Foo(&)[3]); auto jv2 = std::views::join(jv); ASSERT_SAME_TYPE(std::ranges::range_reference_t, Foo&); assert(&(*jv2.begin()) == &nested[0][0][0]); } { // Test `v | views::join` ForwardCommonInner inners[3] = {buffer1, buffer2, buffer3}; using Result = std::ranges::join_view>; std::same_as decltype(auto) v = inners | std::views::join; assert(std::ranges::next(v.begin(), 9) == v.end()); assert(&(*v.begin()) == buffer1); static_assert(CanBePiped); } { // Test `move-only-view | views::join` ForwardCommonInner inners[3] = {buffer1, buffer2, buffer3}; using Result = std::ranges::join_view; std::same_as decltype(auto) v = MoveOnlyOuter{inners} | std::views::join; assert(std::ranges::next(v.begin(), 9) == v.end()); assert(&(*v.begin()) == buffer1); static_assert(CanBePiped); static_assert(!CanBePiped); } { // LWG3474 Nesting `join_views` is broken because of CTAD // join_view | views::join should join the view instead of calling copy constructor auto jv = nested | std::views::join | std::views::join; ASSERT_SAME_TYPE(std::ranges::range_reference_t, Foo&); assert(&(*jv.begin()) == &nested[0][0][0]); static_assert(CanBePiped); } { // Test `adaptor | views::join` auto join_twice = std::views::join | std::views::join; auto jv = nested | join_twice; ASSERT_SAME_TYPE(std::ranges::range_reference_t, Foo&); assert(&(*jv.begin()) == &nested[0][0][0]); static_assert(CanBePiped); } { static_assert(!CanBePiped); static_assert(!CanBePiped); static_assert(!CanBePiped); static_assert(CanBePiped); } return true; } int main(int, char**) { test(); static_assert(test()); return 0; }