xref: /llvm-project/libcxx/test/std/ranges/range.adaptors/range.transform/adaptor.pass.cpp (revision ba2236d3000645d3127f972aa7ac1844c47e299c)
1 //===----------------------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 // UNSUPPORTED: c++03, c++11, c++14, c++17
10 
11 // std::views::transform
12 
13 #include <ranges>
14 
15 #include <cassert>
16 #include <concepts>
17 #include <type_traits>
18 #include <utility>
19 
20 #include "test_macros.h"
21 #include "test_range.h"
22 #include "types.h"
23 
24 struct NonCopyableFunction {
25   NonCopyableFunction(NonCopyableFunction const&) = delete;
26   template <class T>
operator ()NonCopyableFunction27   constexpr T operator()(T x) const { return x; }
28 };
29 
test()30 constexpr bool test() {
31   int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7};
32 
33   // Test `views::transform(f)(v)`
34   {
35     {
36       using Result = std::ranges::transform_view<MoveOnlyView, PlusOne>;
37       std::same_as<Result> auto result = std::views::transform(PlusOne{})(MoveOnlyView{buff});
38       assert(result.begin().base() == buff);
39       assert(result[0] == 1);
40       assert(result[1] == 2);
41       assert(result[2] == 3);
42     }
43     {
44       auto const partial = std::views::transform(PlusOne{});
45       using Result = std::ranges::transform_view<MoveOnlyView, PlusOne>;
46       std::same_as<Result> auto result = partial(MoveOnlyView{buff});
47       assert(result.begin().base() == buff);
48       assert(result[0] == 1);
49       assert(result[1] == 2);
50       assert(result[2] == 3);
51     }
52   }
53 
54   // Test `v | views::transform(f)`
55   {
56     {
57       using Result = std::ranges::transform_view<MoveOnlyView, PlusOne>;
58       std::same_as<Result> auto result = MoveOnlyView{buff} | std::views::transform(PlusOne{});
59       assert(result.begin().base() == buff);
60       assert(result[0] == 1);
61       assert(result[1] == 2);
62       assert(result[2] == 3);
63     }
64     {
65       auto const partial = std::views::transform(PlusOne{});
66       using Result = std::ranges::transform_view<MoveOnlyView, PlusOne>;
67       std::same_as<Result> auto result = MoveOnlyView{buff} | partial;
68       assert(result.begin().base() == buff);
69       assert(result[0] == 1);
70       assert(result[1] == 2);
71       assert(result[2] == 3);
72     }
73   }
74 
75   // Test `views::transform(v, f)`
76   {
77     using Result = std::ranges::transform_view<MoveOnlyView, PlusOne>;
78     std::same_as<Result> auto result = std::views::transform(MoveOnlyView{buff}, PlusOne{});
79     assert(result.begin().base() == buff);
80     assert(result[0] == 1);
81     assert(result[1] == 2);
82     assert(result[2] == 3);
83   }
84 
85   // Test that one can call std::views::transform with arbitrary stuff, as long as we
86   // don't try to actually complete the call by passing it a range.
87   //
88   // That makes no sense and we can't do anything with the result, but it's valid.
89   {
90     struct X { };
91     auto partial = std::views::transform(X{});
92     (void)partial;
93   }
94 
95   // Test `adaptor | views::transform(f)`
96   {
97     {
98       using Result = std::ranges::transform_view<std::ranges::transform_view<MoveOnlyView, PlusOne>, TimesTwo>;
99       std::same_as<Result> auto result = MoveOnlyView{buff} | std::views::transform(PlusOne{}) | std::views::transform(TimesTwo{});
100       assert(result.begin().base().base() == buff);
101       assert(result[0] == 2);
102       assert(result[1] == 4);
103       assert(result[2] == 6);
104     }
105     {
106       auto const partial = std::views::transform(PlusOne{}) | std::views::transform(TimesTwo{});
107       using Result = std::ranges::transform_view<std::ranges::transform_view<MoveOnlyView, PlusOne>, TimesTwo>;
108       std::same_as<Result> auto result = MoveOnlyView{buff} | partial;
109       assert(result.begin().base().base() == buff);
110       assert(result[0] == 2);
111       assert(result[1] == 4);
112       assert(result[2] == 6);
113     }
114   }
115 
116   // Test SFINAE friendliness
117   {
118     struct NotAView { };
119     struct NotInvocable { };
120 
121     static_assert(!CanBePiped<MoveOnlyView, decltype(std::views::transform)>);
122     static_assert( CanBePiped<MoveOnlyView, decltype(std::views::transform(PlusOne{}))>);
123     static_assert(!CanBePiped<NotAView,       decltype(std::views::transform(PlusOne{}))>);
124     static_assert(!CanBePiped<MoveOnlyView, decltype(std::views::transform(NotInvocable{}))>);
125 
126     static_assert(!std::is_invocable_v<decltype(std::views::transform)>);
127     static_assert(!std::is_invocable_v<decltype(std::views::transform), PlusOne, MoveOnlyView>);
128     static_assert( std::is_invocable_v<decltype(std::views::transform), MoveOnlyView, PlusOne>);
129     static_assert(!std::is_invocable_v<decltype(std::views::transform), MoveOnlyView, PlusOne, PlusOne>);
130     static_assert(!std::is_invocable_v<decltype(std::views::transform), NonCopyableFunction>);
131   }
132 
133   {
134     static_assert(std::is_same_v<decltype(std::ranges::views::transform), decltype(std::views::transform)>);
135   }
136 
137   return true;
138 }
139 
main(int,char **)140 int main(int, char**) {
141   test();
142   static_assert(test());
143 
144   return 0;
145 }
146