1 /*
2 * Copyright (c) Facebook, Inc. and its affiliates.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <folly/Replaceable.h>
18
19 #include <folly/portability/GTest.h>
20
21 using namespace ::testing;
22 using namespace ::folly;
23
24 namespace {
25 struct Basic {};
26 struct alignas(128) BigAlign {};
27 struct HasConst final {
28 bool const b1;
HasConst__anon1b2344a00111::HasConst29 HasConst() noexcept : b1(true) {}
HasConst__anon1b2344a00111::HasConst30 explicit HasConst(bool b) noexcept : b1(b) {}
HasConst__anon1b2344a00111::HasConst31 HasConst(HasConst const& b) noexcept : b1(b.b1) {}
HasConst__anon1b2344a00111::HasConst32 HasConst(HasConst&& b) noexcept : b1(b.b1) {}
33 HasConst& operator=(HasConst const&) = delete;
34 HasConst& operator=(HasConst&&) = delete;
35 };
36 struct HasRef final {
37 int& i1;
HasRef__anon1b2344a00111::HasRef38 explicit HasRef(int& i) noexcept(false) : i1(i) {}
HasRef__anon1b2344a00111::HasRef39 HasRef(HasRef const& i) noexcept(false) : i1(i.i1) {}
HasRef__anon1b2344a00111::HasRef40 HasRef(HasRef&& i) noexcept(false) : i1(i.i1) {}
41 HasRef& operator=(HasRef const&) = delete;
42 HasRef& operator=(HasRef&&) = delete;
~HasRef__anon1b2344a00111::HasRef43 ~HasRef() noexcept(false) { ++i1; }
44 };
swap(HasRef & lhs,HasRef & rhs)45 void swap(HasRef& lhs, HasRef& rhs) noexcept(false) {
46 std::swap(lhs.i1, rhs.i1);
47 }
48 struct OddA;
49 struct OddB {
50 OddB() = delete;
OddB__anon1b2344a00111::OddB51 OddB(std::initializer_list<int>, int) noexcept(false) {}
OddB__anon1b2344a00111::OddB52 explicit OddB(OddA&&) {}
OddB__anon1b2344a00111::OddB53 explicit OddB(OddA const&) noexcept(false) {}
54 OddB(OddB&&) = delete;
55 OddB(OddB const&) = delete;
56 OddB& operator=(OddB&&) = delete;
57 OddB& operator=(OddB const&) = delete;
58 ~OddB() = default;
59 };
60 struct OddA {
61 OddA() = delete;
OddA__anon1b2344a00111::OddA62 explicit OddA(OddB&&) noexcept {}
63 explicit OddA(OddB const&) = delete;
64 OddA(OddA&&) = delete;
65 OddA(OddA const&) = delete;
66 OddA& operator=(OddA&&) = delete;
67 OddA& operator=(OddA const&) = delete;
~OddA__anon1b2344a00111::OddA68 ~OddA() noexcept(false) {}
69 };
70 struct Indestructible {
71 ~Indestructible() = delete;
72 };
73
74 struct HasInt {
HasInt__anon1b2344a00111::HasInt75 explicit HasInt(int v) : value{v} {}
76 int value{};
77 };
78 } // namespace
79
80 template <typename T>
81 struct ReplaceableStaticAttributeTest : Test {};
82 using StaticAttributeTypes = ::testing::Types<
83 char,
84 short,
85 int,
86 long,
87 float,
88 double,
89 char[11],
90 Basic,
91 BigAlign,
92 HasConst,
93 HasRef,
94 OddA,
95 OddB,
96 Indestructible>;
97 TYPED_TEST_SUITE(ReplaceableStaticAttributeTest, StaticAttributeTypes);
98
99 template <typename T>
100 struct ReplaceableStaticAttributePairTest : Test {};
101 using StaticAttributePairTypes = ::testing::
102 Types<std::pair<int, long>, std::pair<OddA, OddB>, std::pair<OddB, OddA>>;
103 TYPED_TEST_SUITE(ReplaceableStaticAttributePairTest, StaticAttributePairTypes);
104
TYPED_TEST(ReplaceableStaticAttributeTest,size)105 TYPED_TEST(ReplaceableStaticAttributeTest, size) {
106 EXPECT_EQ(sizeof(TypeParam), sizeof(Replaceable<TypeParam>));
107 }
TYPED_TEST(ReplaceableStaticAttributeTest,align)108 TYPED_TEST(ReplaceableStaticAttributeTest, align) {
109 EXPECT_EQ(alignof(TypeParam), alignof(Replaceable<TypeParam>));
110 }
TYPED_TEST(ReplaceableStaticAttributeTest,destructible)111 TYPED_TEST(ReplaceableStaticAttributeTest, destructible) {
112 EXPECT_EQ(
113 std::is_destructible<TypeParam>::value,
114 std::is_destructible<Replaceable<TypeParam>>::value);
115 }
TYPED_TEST(ReplaceableStaticAttributeTest,trivially_destructible)116 TYPED_TEST(ReplaceableStaticAttributeTest, trivially_destructible) {
117 EXPECT_EQ(
118 std::is_trivially_destructible<TypeParam>::value,
119 std::is_trivially_destructible<Replaceable<TypeParam>>::value);
120 }
TYPED_TEST(ReplaceableStaticAttributeTest,default_constructible)121 TYPED_TEST(ReplaceableStaticAttributeTest, default_constructible) {
122 EXPECT_EQ(
123 std::is_default_constructible<TypeParam>::value,
124 std::is_default_constructible<Replaceable<TypeParam>>::value);
125 }
TYPED_TEST(ReplaceableStaticAttributeTest,move_constructible)126 TYPED_TEST(ReplaceableStaticAttributeTest, move_constructible) {
127 EXPECT_EQ(
128 std::is_move_constructible<TypeParam>::value,
129 std::is_move_constructible<Replaceable<TypeParam>>::value);
130 }
TYPED_TEST(ReplaceableStaticAttributeTest,copy_constructible)131 TYPED_TEST(ReplaceableStaticAttributeTest, copy_constructible) {
132 EXPECT_EQ(
133 std::is_copy_constructible<TypeParam>::value,
134 std::is_copy_constructible<Replaceable<TypeParam>>::value);
135 }
TYPED_TEST(ReplaceableStaticAttributeTest,move_assignable)136 TYPED_TEST(ReplaceableStaticAttributeTest, move_assignable) {
137 EXPECT_EQ(
138 std::is_move_constructible<TypeParam>::value,
139 std::is_move_assignable<Replaceable<TypeParam>>::value);
140 }
TYPED_TEST(ReplaceableStaticAttributeTest,copy_assignable)141 TYPED_TEST(ReplaceableStaticAttributeTest, copy_assignable) {
142 EXPECT_EQ(
143 std::is_copy_constructible<TypeParam>::value,
144 std::is_copy_assignable<Replaceable<TypeParam>>::value);
145 }
TYPED_TEST(ReplaceableStaticAttributeTest,nothrow_destructible)146 TYPED_TEST(ReplaceableStaticAttributeTest, nothrow_destructible) {
147 EXPECT_EQ(
148 std::is_nothrow_destructible<TypeParam>::value,
149 std::is_nothrow_destructible<Replaceable<TypeParam>>::value);
150 }
TYPED_TEST(ReplaceableStaticAttributeTest,nothrow_default_constructible)151 TYPED_TEST(ReplaceableStaticAttributeTest, nothrow_default_constructible) {
152 EXPECT_EQ(
153 std::is_nothrow_default_constructible<TypeParam>::value,
154 std::is_nothrow_default_constructible<Replaceable<TypeParam>>::value);
155 }
TYPED_TEST(ReplaceableStaticAttributeTest,nothrow_move_constructible)156 TYPED_TEST(ReplaceableStaticAttributeTest, nothrow_move_constructible) {
157 EXPECT_EQ(
158 std::is_nothrow_move_constructible<TypeParam>::value,
159 std::is_nothrow_move_constructible<Replaceable<TypeParam>>::value);
160 }
TYPED_TEST(ReplaceableStaticAttributeTest,nothrow_copy_constructible)161 TYPED_TEST(ReplaceableStaticAttributeTest, nothrow_copy_constructible) {
162 EXPECT_EQ(
163 std::is_nothrow_copy_constructible<TypeParam>::value,
164 std::is_nothrow_copy_constructible<Replaceable<TypeParam>>::value);
165 }
TYPED_TEST(ReplaceableStaticAttributeTest,nothrow_move_assignable)166 TYPED_TEST(ReplaceableStaticAttributeTest, nothrow_move_assignable) {
167 EXPECT_EQ(
168 std::is_nothrow_destructible<TypeParam>::value &&
169 std::is_nothrow_copy_constructible<TypeParam>::value,
170 std::is_nothrow_move_assignable<Replaceable<TypeParam>>::value);
171 }
TYPED_TEST(ReplaceableStaticAttributeTest,nothrow_copy_assignable)172 TYPED_TEST(ReplaceableStaticAttributeTest, nothrow_copy_assignable) {
173 EXPECT_EQ(
174 std::is_nothrow_destructible<TypeParam>::value &&
175 std::is_nothrow_copy_constructible<TypeParam>::value,
176 std::is_nothrow_copy_assignable<Replaceable<TypeParam>>::value);
177 }
TYPED_TEST(ReplaceableStaticAttributeTest,replaceable)178 TYPED_TEST(ReplaceableStaticAttributeTest, replaceable) {
179 EXPECT_FALSE(is_replaceable<TypeParam>::value);
180 EXPECT_TRUE(is_replaceable<Replaceable<TypeParam>>::value);
181 }
182
TYPED_TEST(ReplaceableStaticAttributePairTest,copy_construct)183 TYPED_TEST(ReplaceableStaticAttributePairTest, copy_construct) {
184 using T = typename TypeParam::first_type;
185 using U = typename TypeParam::second_type;
186 EXPECT_EQ(
187 (std::is_constructible<T, U const&>::value),
188 (std::is_constructible<Replaceable<T>, Replaceable<U> const&>::value));
189 }
TYPED_TEST(ReplaceableStaticAttributePairTest,move_construct)190 TYPED_TEST(ReplaceableStaticAttributePairTest, move_construct) {
191 using T = typename TypeParam::first_type;
192 using U = typename TypeParam::second_type;
193 EXPECT_EQ(
194 (std::is_constructible<T, U&&>::value),
195 (std::is_constructible<Replaceable<T>, Replaceable<U>&&>::value));
196 }
TYPED_TEST(ReplaceableStaticAttributePairTest,copy_assign)197 TYPED_TEST(ReplaceableStaticAttributePairTest, copy_assign) {
198 using T = typename TypeParam::first_type;
199 using U = typename TypeParam::second_type;
200 EXPECT_EQ(
201 (std::is_convertible<U, T>::value && std::is_destructible<T>::value &&
202 std::is_copy_constructible<T>::value),
203 (std::is_assignable<Replaceable<T>, Replaceable<U> const&>::value));
204 }
TYPED_TEST(ReplaceableStaticAttributePairTest,move_assign)205 TYPED_TEST(ReplaceableStaticAttributePairTest, move_assign) {
206 using T = typename TypeParam::first_type;
207 using U = typename TypeParam::second_type;
208 EXPECT_EQ(
209 (std::is_convertible<U, T>::value && std::is_destructible<T>::value &&
210 std::is_move_constructible<T>::value),
211 (std::is_assignable<Replaceable<T>, Replaceable<U>&&>::value));
212 }
TYPED_TEST(ReplaceableStaticAttributePairTest,nothrow_copy_construct)213 TYPED_TEST(ReplaceableStaticAttributePairTest, nothrow_copy_construct) {
214 using T = typename TypeParam::first_type;
215 using U = typename TypeParam::second_type;
216 EXPECT_EQ(
217 (std::is_nothrow_constructible<T, U const&>::value &&
218 std::is_nothrow_destructible<T>::value),
219 (std::is_nothrow_constructible<Replaceable<T>, Replaceable<U> const&>::
220 value));
221 }
TYPED_TEST(ReplaceableStaticAttributePairTest,nothrow_move_construct)222 TYPED_TEST(ReplaceableStaticAttributePairTest, nothrow_move_construct) {
223 using T = typename TypeParam::first_type;
224 using U = typename TypeParam::second_type;
225 EXPECT_EQ(
226 (std::is_nothrow_constructible<T, U&&>::value &&
227 std::is_nothrow_destructible<T>::value),
228 (std::is_nothrow_constructible<Replaceable<T>, Replaceable<U>&&>::value));
229 }
TYPED_TEST(ReplaceableStaticAttributePairTest,nothrow_copy_assign)230 TYPED_TEST(ReplaceableStaticAttributePairTest, nothrow_copy_assign) {
231 using T = typename TypeParam::first_type;
232 using U = typename TypeParam::second_type;
233 EXPECT_EQ(
234 (std::is_nothrow_constructible<T, U const&>::value &&
235 std::is_nothrow_destructible<T>::value),
236 (std::is_nothrow_assignable<Replaceable<T>, Replaceable<U> const&>::
237 value));
238 }
TYPED_TEST(ReplaceableStaticAttributePairTest,nothrow_move_assign)239 TYPED_TEST(ReplaceableStaticAttributePairTest, nothrow_move_assign) {
240 using T = typename TypeParam::first_type;
241 using U = typename TypeParam::second_type;
242 EXPECT_EQ(
243 (std::is_nothrow_constructible<T, U&&>::value &&
244 std::is_nothrow_destructible<T>::value),
245 (std::is_nothrow_assignable<Replaceable<T>, Replaceable<U>&&>::value));
246 }
247
TEST(ReplaceableTest,Basics)248 TEST(ReplaceableTest, Basics) {
249 auto rHasConstA = make_replaceable<HasConst>();
250 auto rHasConstB = make_replaceable<HasConst>(false);
251 EXPECT_TRUE(rHasConstA->b1);
252 EXPECT_FALSE(rHasConstB->b1);
253 rHasConstA = rHasConstB;
254 EXPECT_FALSE(rHasConstA->b1);
255 EXPECT_FALSE(rHasConstB->b1);
256 rHasConstB.emplace(true);
257 EXPECT_FALSE(rHasConstA->b1);
258 EXPECT_TRUE(rHasConstB->b1);
259 rHasConstA = std::move(rHasConstB);
260 EXPECT_TRUE(rHasConstA->b1);
261 EXPECT_TRUE(rHasConstB->b1);
262 }
263
TEST(ReplaceableTest,Constructors)264 TEST(ReplaceableTest, Constructors) {
265 Basic b{};
266 // From existing `T`
267 auto rBasicCopy1 = Replaceable<Basic>(b);
268 auto rBasicMove1 = Replaceable<Basic>(std::move(b));
269 // From existing `Replaceable<T>`
270 auto rBasicCopy2 = Replaceable<Basic>(rBasicCopy1);
271 auto rBasicMove2 = Replaceable<Basic>(std::move(rBasicMove1));
272 (void)rBasicCopy2;
273 (void)rBasicMove2;
274 }
275
TEST(ReplaceableTest,DestructsWhenExpected)276 TEST(ReplaceableTest, DestructsWhenExpected) {
277 int i{0};
278 {
279 Replaceable<HasRef> rHasRefA{i};
280 Replaceable<HasRef> rHasRefB{i};
281 EXPECT_EQ(0, i);
282 rHasRefA = rHasRefB;
283 EXPECT_EQ(1, i);
284 rHasRefB.emplace(i);
285 EXPECT_EQ(2, i);
286 rHasRefA = std::move(rHasRefB);
287 EXPECT_EQ(3, i);
288 }
289 EXPECT_EQ(5, i);
290 }
291
TEST(ReplaceableTest,Conversions)292 TEST(ReplaceableTest, Conversions) {
293 Replaceable<OddB> rOddB{in_place, {1, 2, 3}, 4};
294 Replaceable<OddA> rOddA{std::move(rOddB)};
295 Replaceable<OddB> rOddB2{rOddA};
296 }
297
TEST(ReplaceableTest,swapMemberFunctionIsNoexcept)298 TEST(ReplaceableTest, swapMemberFunctionIsNoexcept) {
299 int v1{1};
300 int v2{2};
301 auto r1 = Replaceable<HasInt>{v1};
302 auto r2 = Replaceable<HasInt>{v2};
303 EXPECT_TRUE(noexcept(r1.swap(r2)));
304 r1.swap(r2);
305 EXPECT_EQ(v2, r1->value);
306 EXPECT_EQ(v1, r2->value);
307 }
308
TEST(ReplaceableTest,swapMemberFunctionIsNotNoexcept)309 TEST(ReplaceableTest, swapMemberFunctionIsNotNoexcept) {
310 int v1{1};
311 int v2{2};
312 auto r1 = Replaceable<HasRef>{v1};
313 auto r2 = Replaceable<HasRef>{v2};
314 EXPECT_FALSE(noexcept(r1.swap(r2)));
315 r1.swap(r2);
316 EXPECT_EQ(v1, r1->i1);
317 EXPECT_EQ(v2, r2->i1);
318 }
319
320 namespace adl_test {
321 struct UserDefinedSwap {
322 bool calledSwap{};
323 };
swap(UserDefinedSwap & lhs,UserDefinedSwap &)324 void swap(UserDefinedSwap& lhs, UserDefinedSwap&) noexcept(false) {
325 lhs.calledSwap = true;
326 }
327 } // namespace adl_test
328
TEST(ReplaceableTest,swapMemberFunctionDelegatesToUserSwap)329 TEST(ReplaceableTest, swapMemberFunctionDelegatesToUserSwap) {
330 auto r1 = Replaceable<adl_test::UserDefinedSwap>{};
331 auto r2 = Replaceable<adl_test::UserDefinedSwap>{};
332 r1.swap(r2);
333 EXPECT_TRUE(r1->calledSwap);
334 }
335
336 #if __cpp_deduction_guides >= 201703
TEST(ReplaceableTest,DeductionGuide)337 TEST(ReplaceableTest, DeductionGuide) {
338 Basic b{};
339 Replaceable r{b};
340 EXPECT_TRUE((std::is_same_v<Replaceable<Basic>, decltype(r)>));
341 }
342 #endif
343