1#include <c10/util/C++17.h>
2#include <gtest/gtest.h>
3
4namespace {
5
6namespace test_min {
7using c10::guts::min;
8static_assert(min(3, 5) == 3, "");
9static_assert(min(5, 3) == 3, "");
10static_assert(min(3, 3) == 3, "");
11static_assert(min(3.0, 3.1) == 3.0, "");
12} // namespace test_min
13
14namespace test_max {
15using c10::guts::max;
16static_assert(max(3, 5) == 5, "");
17static_assert(max(5, 3) == 5, "");
18static_assert(max(3, 3) == 3, "");
19static_assert(max(3.0, 3.1) == 3.1, "");
20} // namespace test_max
21
22namespace test_if_constexpr {
23
24using c10::guts::if_constexpr;
25
26TEST(if_constexpr, whenIsTrue_thenReturnsTrueCase) {
27 EXPECT_EQ(
28 4, if_constexpr<true>([](auto) { return 4; }, [](auto) { return 5; }));
29}
30
31TEST(if_constexpr, whenIsFalse_thenReturnsFalseCase) {
32 EXPECT_EQ(
33 5, if_constexpr<false>([](auto) { return 4; }, [](auto) { return 5; }));
34}
35
36struct MovableOnly final {
37 int value;
38
39 MovableOnly(int v) : value(v) {}
40 MovableOnly(MovableOnly&&) = default;
41 MovableOnly(const MovableOnly&) = delete;
42 MovableOnly& operator=(MovableOnly&&) = default;
43 MovableOnly& operator=(const MovableOnly&) = delete;
44};
45
46TEST(if_constexpr, worksWithMovableOnlyTypes_withIdentityArg) {
47 EXPECT_EQ(
48 4,
49 if_constexpr<true>(
50 [](auto) { return MovableOnly(4); },
51 [](auto) { return MovableOnly(5); })
52 .value);
53 EXPECT_EQ(
54 5,
55 if_constexpr<false>(
56 [](auto) { return MovableOnly(4); },
57 [](auto) { return MovableOnly(5); })
58 .value);
59}
60
61TEST(if_constexpr, worksWithMovableOnlyTypes_withoutIdentityArg) {
62 EXPECT_EQ(
63 4,
64 if_constexpr<true>(
65 [] { return MovableOnly(4); }, [] { return MovableOnly(5); })
66 .value);
67 EXPECT_EQ(
68 5,
69 if_constexpr<false>(
70 [] { return MovableOnly(4); }, [] { return MovableOnly(5); })
71 .value);
72}
73
74struct MyClass1 {
75 int value;
76};
77
78struct MyClass2 {
79 int val;
80};
81
82template <class T>
83int func(T t) {
84 return if_constexpr<std::is_same<T, MyClass1>::value>(
85 [&](auto _) {
86 return _(t).value;
87 }, // this code is invalid for T == MyClass2
88 [&](auto _) { return _(t).val; } // this code is invalid for T == MyClass1
89 );
90}
91
92TEST(if_constexpr, otherCaseCanHaveInvalidCode) {
93 EXPECT_EQ(8, func(MyClass1{/* .value = */ 8}));
94 EXPECT_EQ(4, func(MyClass2{/* .val = */ 4}));
95}
96
97TEST(if_constexpr, worksWithoutElseCase_withIdentityArg) {
98 int var = 5;
99 if_constexpr<false>([&](auto) { var = 3; });
100 EXPECT_EQ(5, var);
101 if_constexpr<true>([&](auto) { var = 3; });
102 EXPECT_EQ(3, var);
103}
104
105TEST(if_constexpr, worksWithoutElseCase_withoutIdentityArg) {
106 int var = 5;
107 if_constexpr<false>([&] { var = 3; });
108 EXPECT_EQ(5, var);
109 if_constexpr<true>([&] { var = 3; });
110 EXPECT_EQ(3, var);
111}
112
113TEST(if_constexpr, returnTypeCanDiffer_withIdentityArg) {
114 auto a_string = if_constexpr<false>(
115 [&](auto) -> int64_t { return 3; },
116 [&](auto) -> std::string { return "3"; });
117 static_assert(std::is_same<std::string, decltype(a_string)>::value, "");
118
119 // NOLINTNEXTLINE(clang-analyzer-deadcode.DeadStores)
120 auto an_int = if_constexpr<true>(
121 [&](auto) -> int64_t { return 3; },
122 [&](auto) -> std::string { return "3"; });
123 static_assert(std::is_same<int64_t, decltype(an_int)>::value, "");
124}
125
126TEST(if_constexpr, returnTypeCanDiffer_withoutIdentityArg) {
127 auto a_string = if_constexpr<false>(
128 [&]() -> int64_t { return 3; }, [&]() -> std::string { return "3"; });
129 static_assert(std::is_same<std::string, decltype(a_string)>::value, "");
130
131 // NOLINTNEXTLINE(clang-analyzer-deadcode.DeadStores)
132 auto an_int = if_constexpr<true>(
133 [&]() -> int64_t { return 3; }, [&]() -> std::string { return "3"; });
134 static_assert(std::is_same<int64_t, decltype(an_int)>::value, "");
135}
136
137} // namespace test_if_constexpr
138} // namespace
139