xref: /aosp_15_r20/external/pytorch/c10/test/util/Metaprogramming_test.cpp (revision da0073e96a02ea20f0ac840b70461e3646d07c45)
1 #include <c10/test/util/Macros.h>
2 #include <c10/util/Metaprogramming.h>
3 #include <gtest/gtest.h>
4 #include <cstdlib>
5 
6 using namespace c10::guts;
7 
8 // NOLINTBEGIN(modernize*)
9 namespace {
10 
11 namespace test_function_traits {
12 static_assert(
13     std::is_same<
14         void,
15         typename function_traits<void(int, float)>::return_type>::value,
16     "");
17 static_assert(
18     std::is_same<int, typename function_traits<int(int, float)>::return_type>::
19         value,
20     "");
21 static_assert(
22     std::is_same<
23         typelist::typelist<int, float>,
24         typename function_traits<void(int, float)>::parameter_types>::value,
25     "");
26 static_assert(
27     std::is_same<
28         typelist::typelist<int, float>,
29         typename function_traits<int(int, float)>::parameter_types>::value,
30     "");
31 
32 static_assert(
33     std::is_same<
34         bool,
35         typename make_function_traits_t<bool, typelist::typelist<int, float>>::
36             return_type>::value,
37     "");
38 static_assert(
39     std::is_same<
40         void,
41         typename make_function_traits_t<void, typelist::typelist<int, float>>::
42             return_type>::value,
43     "");
44 static_assert(
45     std::is_same<
46         typelist::typelist<int, float>,
47         typename make_function_traits_t<bool, typelist::typelist<int, float>>::
48             parameter_types>::value,
49     "");
50 static_assert(
51     std::is_same<
52         typelist::typelist<int, float>,
53         typename make_function_traits_t<void, typelist::typelist<int, float>>::
54             parameter_types>::value,
55     "");
56 static_assert(
57     std::is_same<
58         bool(int, float),
59         typename make_function_traits_t<bool, typelist::typelist<int, float>>::
60             func_type>::value,
61     "");
62 static_assert(
63     std::is_same<
64         void(int, float),
65         typename make_function_traits_t<void, typelist::typelist<int, float>>::
66             func_type>::value,
67     "");
68 } // namespace test_function_traits
69 
70 struct MovableOnly {
MovableOnly__anonbe8862e80111::MovableOnly71   constexpr MovableOnly(int val_) : val(val_) { /* no default constructor */
72   }
73   MovableOnly(const MovableOnly&) = delete;
74   MovableOnly(MovableOnly&&) = default;
75   MovableOnly& operator=(const MovableOnly&) = delete;
76   MovableOnly& operator=(MovableOnly&&) = default;
77 
operator ==(const MovableOnly & lhs,const MovableOnly & rhs)78   friend bool operator==(const MovableOnly& lhs, const MovableOnly& rhs) {
79     return lhs.val == rhs.val;
80   }
81 
82  private:
83   int val;
84 };
85 
86 template <class T>
87 using is_my_movable_only_class =
88     std::is_same<MovableOnly, std::remove_cv_t<std::remove_reference_t<T>>>;
89 
90 struct CopyCounting {
91   int move_count;
92   int copy_count;
93 
CopyCounting__anonbe8862e80111::CopyCounting94   CopyCounting() : move_count(0), copy_count(0) {}
CopyCounting__anonbe8862e80111::CopyCounting95   CopyCounting(const CopyCounting& rhs)
96       : move_count(rhs.move_count), copy_count(rhs.copy_count + 1) {}
CopyCounting__anonbe8862e80111::CopyCounting97   CopyCounting(CopyCounting&& rhs) noexcept
98       : move_count(rhs.move_count + 1), copy_count(rhs.copy_count) {}
operator =__anonbe8862e80111::CopyCounting99   CopyCounting& operator=(const CopyCounting& rhs) {
100     move_count = rhs.move_count;
101     copy_count = rhs.copy_count + 1;
102     return *this;
103   }
operator =__anonbe8862e80111::CopyCounting104   CopyCounting& operator=(CopyCounting&& rhs) noexcept {
105     move_count = rhs.move_count + 1;
106     copy_count = rhs.copy_count;
107     return *this;
108   }
109 };
110 
111 template <class T>
112 using is_my_copy_counting_class =
113     std::is_same<CopyCounting, std::remove_cv_t<std::remove_reference_t<T>>>;
114 
115 namespace test_tuple_elements {
116 // note: not testing empty selection, as some compilers will raise
117 // "parameter set but not used" in tuple_elements(). a good example
118 // of the friction that comes with using these tools
119 
TEST(MetaprogrammingTest,TupleElements_subsetSelection)120 TEST(MetaprogrammingTest, TupleElements_subsetSelection) {
121   auto x = std::make_tuple(0, "HEY", 2.0);
122   auto y = tuple_elements(x, std::index_sequence<0, 2>());
123   auto z = std::make_tuple(0, 2.0);
124   EXPECT_EQ(y, z);
125 }
126 
TEST(MetaprogrammingTest,TupleElements_reorderSelection)127 TEST(MetaprogrammingTest, TupleElements_reorderSelection) {
128   auto x = std::make_tuple(0, "HEY", 2.0);
129   auto y = tuple_elements(x, std::index_sequence<0, 2, 1>());
130   auto z = std::make_tuple(0, 2.0, "HEY");
131   EXPECT_EQ(y, z);
132 }
133 } // namespace test_tuple_elements
134 
135 namespace test_tuple_take {
136 // note: not testing empty prefix, see note on empty selection above.
137 
TEST(MetaprogrammingTest,TupleTake_nonemptyPrefix)138 TEST(MetaprogrammingTest, TupleTake_nonemptyPrefix) {
139   auto x = std::make_tuple(0, "HEY", 2.0);
140   auto y = tuple_take<decltype(x), 2>(x);
141   auto z = std::make_tuple(0, "HEY");
142   EXPECT_EQ(y, z);
143 }
144 
TEST(MetaprogrammingTest,TupleTake_fullPrefix)145 TEST(MetaprogrammingTest, TupleTake_fullPrefix) {
146   auto x = std::make_tuple(0, "HEY", 2.0);
147   auto y = tuple_take<decltype(x), 3>(x);
148   EXPECT_EQ(x, y);
149 }
150 
TEST(MetaprogrammingTest,TupleTake_negative)151 TEST(MetaprogrammingTest, TupleTake_negative) {
152   auto x = std::make_tuple(0, "HEY", 2.0);
153   auto y = tuple_take<decltype(x), -2>(x);
154   auto z = std::make_tuple("HEY", 2.0);
155   EXPECT_EQ(y, z);
156 }
157 } // namespace test_tuple_take
158 
159 namespace test_tuple_slice {
TEST(MetaprogrammingTest,TupleSlice_middle)160 TEST(MetaprogrammingTest, TupleSlice_middle) {
161   auto x = std::make_tuple(0, "HEY", 2.0, false);
162   auto y = tuple_slice<decltype(x), 1, 2>(x);
163   auto z = std::make_tuple("HEY", 2.0);
164   EXPECT_EQ(y, z);
165 }
166 
TEST(MetaprogrammingTest,TupleSlice_full)167 TEST(MetaprogrammingTest, TupleSlice_full) {
168   auto x = std::make_tuple(0, "HEY", 2.0);
169   auto y = tuple_slice<decltype(x), 0, 3>(x);
170   EXPECT_EQ(x, y);
171 }
172 } // namespace test_tuple_slice
173 
174 namespace test_tuple_map {
TEST(MetaprogrammingTest,TupleMap_simple)175 TEST(MetaprogrammingTest, TupleMap_simple) {
176   auto result = tuple_map(
177       std::tuple<int32_t, int32_t, int32_t>(3, 4, 5),
178       [](int32_t a) -> int16_t { return static_cast<int16_t>(a + 1); });
179   static_assert(
180       std::is_same<std::tuple<int16_t, int16_t, int16_t>, decltype(result)>::
181           value,
182       "");
183   EXPECT_EQ(4, std::get<0>(result));
184   EXPECT_EQ(5, std::get<1>(result));
185   EXPECT_EQ(6, std::get<2>(result));
186 }
187 
TEST(MetaprogrammingTest,TupleMap_mapperTakesDifferentButConvertibleType)188 TEST(MetaprogrammingTest, TupleMap_mapperTakesDifferentButConvertibleType) {
189   auto result = tuple_map(
190       std::tuple<int32_t, int32_t, int32_t>(3, 4, 5),
191       [](int64_t a) -> int16_t { return static_cast<int16_t>(a + 1); });
192   static_assert(
193       std::is_same<std::tuple<int16_t, int16_t, int16_t>, decltype(result)>::
194           value,
195       "");
196   EXPECT_EQ(4, std::get<0>(result));
197   EXPECT_EQ(5, std::get<1>(result));
198   EXPECT_EQ(6, std::get<2>(result));
199 }
200 
TEST(MetaprogrammingTest,TupleMap_mapperTakesConstRef)201 TEST(MetaprogrammingTest, TupleMap_mapperTakesConstRef) {
202   auto result = tuple_map(
203       std::tuple<int32_t, int32_t, int32_t>(3, 4, 5),
204       [](const int32_t& a) -> int16_t { return static_cast<int16_t>(a + 1); });
205   static_assert(
206       std::is_same<std::tuple<int16_t, int16_t, int16_t>, decltype(result)>::
207           value,
208       "");
209   EXPECT_EQ(4, std::get<0>(result));
210   EXPECT_EQ(5, std::get<1>(result));
211   EXPECT_EQ(6, std::get<2>(result));
212 }
213 
TEST(MetaprogrammingTest,TupleMap_mapsToDifferentTypes)214 TEST(MetaprogrammingTest, TupleMap_mapsToDifferentTypes) {
215   struct Mapper {
216     std::string operator()(int32_t a) const {
217       return std::to_string(a);
218     }
219     int32_t operator()(const std::string& a) const {
220       return atoi(a.c_str());
221     }
222   };
223   auto result = tuple_map(std::tuple<int32_t, std::string>(3, "4"), Mapper());
224   static_assert(
225       std::is_same<std::tuple<std::string, int32_t>, decltype(result)>::value,
226       "");
227   EXPECT_EQ("3", std::get<0>(result));
228   EXPECT_EQ(4, std::get<1>(result));
229 }
230 
TEST(MetaprogrammingTest,TupleMap_differentiatesLRValueReferences)231 TEST(MetaprogrammingTest, TupleMap_differentiatesLRValueReferences) {
232   struct Mapper {
233     std::string operator()(std::string&& a) const {
234       return "moved";
235     }
236     std::string operator()(const std::string& a) const {
237       return "copied";
238     }
239   };
240   std::string str1, str2;
241   auto result = tuple_map(
242       std::tuple<const std::string&, std::string&&>(str1, std::move(str2)),
243       Mapper());
244   static_assert(
245       std::is_same<std::tuple<std::string, std::string>, decltype(result)>::
246           value,
247       "");
248   EXPECT_EQ("copied", std::get<0>(result));
249   EXPECT_EQ("moved", std::get<1>(result));
250 }
251 
TEST(MetaprogrammingTest,TupleMap_canWorkWithMovableOnlyType)252 TEST(MetaprogrammingTest, TupleMap_canWorkWithMovableOnlyType) {
253   auto result = tuple_map(
254       std::tuple<MovableOnly>(MovableOnly(7)), [](MovableOnly a) { return a; });
255   static_assert(
256       std::is_same<std::tuple<MovableOnly>, decltype(result)>::value, "");
257   EXPECT_EQ(MovableOnly(7), std::get<0>(result));
258 }
259 
TEST(MetaprogrammingTest,TupleMap_doesntUnecessarilyCopyValues)260 TEST(MetaprogrammingTest, TupleMap_doesntUnecessarilyCopyValues) {
261   auto result = tuple_map(
262       std::tuple<CopyCounting>(CopyCounting()),
263       [](CopyCounting a) { return a; });
264   static_assert(
265       std::is_same<std::tuple<CopyCounting>, decltype(result)>::value, "");
266   EXPECT_EQ(4, std::get<0>(result).move_count);
267   EXPECT_EQ(0, std::get<0>(result).copy_count);
268 }
269 
TEST(MetaprogrammingTest,TupleMap_doesntUnecessarilyMoveValues)270 TEST(MetaprogrammingTest, TupleMap_doesntUnecessarilyMoveValues) {
271   CopyCounting a;
272   auto result = tuple_map(
273       std::tuple<CopyCounting&&>(std::move(a)),
274       [](CopyCounting&& a) -> CopyCounting&& { return std::move(a); });
275   static_assert(
276       std::is_same<std::tuple<CopyCounting&&>, decltype(result)>::value, "");
277   EXPECT_EQ(&a, &std::get<0>(result));
278   EXPECT_EQ(0, std::get<0>(result).move_count);
279   EXPECT_EQ(0, std::get<0>(result).copy_count);
280 }
281 
TEST(MetaprogrammingTest,TupleMap_canBeUsedWithAutoLambdas)282 TEST(MetaprogrammingTest, TupleMap_canBeUsedWithAutoLambdas) {
283   struct A final {
284     int32_t func() {
285       return 5;
286     }
287   };
288   struct B final {
289     std::string func() {
290       return "5";
291     }
292   };
293   auto result =
294       tuple_map(std::make_tuple(A(), B()), [](auto a) { return a.func(); });
295   static_assert(
296       std::is_same<std::tuple<int32_t, std::string>, decltype(result)>::value,
297       "");
298   EXPECT_EQ(5, std::get<0>(result));
299   EXPECT_EQ("5", std::get<1>(result));
300 }
301 } // namespace test_tuple_map
302 
303 } // namespace
304 // NOLINTEND(modernize*)
305