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
24struct NonCopyableFunction {
25 NonCopyableFunction(NonCopyableFunction const&) = delete;
26 template <class T>
27 constexpr T operator()(T x) const { return x; }
28};
29
30constexpr 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
140int main(int, char**) {
141 test();
142 static_assert(test());
143
144 return 0;
145}
146

source code of libcxx/test/std/ranges/range.adaptors/range.transform/adaptor.pass.cpp