| //===----------------------------------------------------------------------===// |
| // |
| // 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 <ranges> |
| |
| #include <cassert> |
| #include <type_traits> |
| |
| #include "types.h" |
| |
| struct MoveOnlyOuter : SimpleForwardCommonOuter<ForwardCommonInner> { |
| using SimpleForwardCommonOuter<ForwardCommonInner>::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 <class View, class T> |
| concept CanBePiped = requires(View&& view, T&& t) { |
| { std::forward<View>(view) | std::forward<T>(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::ranges::ref_view<ForwardCommonInner[3]>>; |
| std::same_as<Result> 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<MoveOnlyOuter>; |
| std::same_as<Result> 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<decltype(std::views::join), MoveOnlyOuter>); |
| static_assert(!std::invocable<decltype(std::views::join), MoveOnlyOuter&>); |
| } |
| |
| { |
| // 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<decltype(jv)>, Foo(&)[3]); |
| |
| auto jv2 = std::views::join(jv); |
| ASSERT_SAME_TYPE(std::ranges::range_reference_t<decltype(jv2)>, 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::ranges::ref_view<ForwardCommonInner[3]>>; |
| std::same_as<Result> decltype(auto) v = inners | std::views::join; |
| assert(std::ranges::next(v.begin(), 9) == v.end()); |
| assert(&(*v.begin()) == buffer1); |
| static_assert(CanBePiped<decltype((inners)), decltype((std::views::join))>); |
| } |
| |
| { |
| // Test `move-only-view | views::join` |
| ForwardCommonInner inners[3] = {buffer1, buffer2, buffer3}; |
| using Result = std::ranges::join_view<MoveOnlyOuter>; |
| std::same_as<Result> decltype(auto) v = MoveOnlyOuter{inners} | std::views::join; |
| assert(std::ranges::next(v.begin(), 9) == v.end()); |
| assert(&(*v.begin()) == buffer1); |
| |
| static_assert(CanBePiped<MoveOnlyOuter, decltype((std::views::join))>); |
| static_assert(!CanBePiped<MoveOnlyOuter&, decltype((std::views::join))>); |
| } |
| |
| { |
| // 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<decltype(jv)>, Foo&); |
| |
| assert(&(*jv.begin()) == &nested[0][0][0]); |
| static_assert(CanBePiped<decltype((nested)), decltype((std::views::join))>); |
| } |
| |
| { |
| // 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<decltype(jv)>, Foo&); |
| |
| assert(&(*jv.begin()) == &nested[0][0][0]); |
| static_assert(CanBePiped<decltype((nested)), decltype((join_twice))>); |
| } |
| |
| { |
| static_assert(!CanBePiped<int, decltype((std::views::join))>); |
| static_assert(!CanBePiped<Foo, decltype((std::views::join))>); |
| static_assert(!CanBePiped<int(&)[2], decltype((std::views::join))>); |
| static_assert(CanBePiped<int(&)[2][2], decltype((std::views::join))>); |
| } |
| |
| return true; |
| } |
| |
| int main(int, char**) { |
| test(); |
| static_assert(test()); |
| |
| return 0; |
| } |