2 * Copyright 2004-present Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include <folly/Replaceable.h>
19 #include <folly/portability/GTest.h>
21 using namespace ::testing;
22 using namespace ::folly;
26 struct alignas(128) BigAlign {};
27 struct HasConst final {
29 HasConst() noexcept : b1(true) {}
30 explicit HasConst(bool b) noexcept : b1(b) {}
31 HasConst(HasConst const& b) noexcept : b1(b.b1) {}
32 HasConst(HasConst&& b) noexcept : b1(b.b1) {}
33 HasConst& operator=(HasConst const&) = delete;
34 HasConst& operator=(HasConst&&) = delete;
38 explicit HasRef(int& i) noexcept(false) : i1(i) {}
39 HasRef(HasRef const& i) noexcept(false) : i1(i.i1) {}
40 HasRef(HasRef&& i) noexcept(false) : i1(i.i1) {}
41 HasRef& operator=(HasRef const&) = delete;
42 HasRef& operator=(HasRef&&) = delete;
43 ~HasRef() noexcept(false) {
51 OddB(std::initializer_list<int>, int) noexcept(false) {}
52 explicit OddB(OddA&&) {}
53 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;
62 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;
68 ~OddA() noexcept(false) {}
70 struct Indestructible {
71 ~Indestructible() = delete;
76 struct ReplaceableStaticAttributeTest : Test {};
77 using StaticAttributeTypes = ::testing::Types<
92 TYPED_TEST_CASE(ReplaceableStaticAttributeTest, StaticAttributeTypes);
95 struct ReplaceableStaticAttributePairTest : Test {};
96 using StaticAttributePairTypes = ::testing::
97 Types<std::pair<int, long>, std::pair<OddA, OddB>, std::pair<OddB, OddA>>;
98 TYPED_TEST_CASE(ReplaceableStaticAttributePairTest, StaticAttributePairTypes);
100 TYPED_TEST(ReplaceableStaticAttributeTest, size) {
101 EXPECT_EQ(sizeof(TypeParam), sizeof(Replaceable<TypeParam>));
103 TYPED_TEST(ReplaceableStaticAttributeTest, align) {
104 EXPECT_EQ(alignof(TypeParam), alignof(Replaceable<TypeParam>));
106 TYPED_TEST(ReplaceableStaticAttributeTest, destructible) {
108 std::is_destructible<TypeParam>::value,
109 std::is_destructible<Replaceable<TypeParam>>::value);
111 TYPED_TEST(ReplaceableStaticAttributeTest, trivially_destructible) {
113 std::is_trivially_destructible<TypeParam>::value,
114 std::is_trivially_destructible<Replaceable<TypeParam>>::value);
116 TYPED_TEST(ReplaceableStaticAttributeTest, default_constructible) {
118 std::is_default_constructible<TypeParam>::value,
119 std::is_default_constructible<Replaceable<TypeParam>>::value);
121 TYPED_TEST(ReplaceableStaticAttributeTest, move_constructible) {
123 std::is_move_constructible<TypeParam>::value,
124 std::is_move_constructible<Replaceable<TypeParam>>::value);
126 TYPED_TEST(ReplaceableStaticAttributeTest, copy_constructible) {
128 std::is_copy_constructible<TypeParam>::value,
129 std::is_copy_constructible<Replaceable<TypeParam>>::value);
131 TYPED_TEST(ReplaceableStaticAttributeTest, move_assignable) {
133 std::is_move_constructible<TypeParam>::value,
134 std::is_move_assignable<Replaceable<TypeParam>>::value);
136 TYPED_TEST(ReplaceableStaticAttributeTest, copy_assignable) {
138 std::is_copy_constructible<TypeParam>::value,
139 std::is_copy_assignable<Replaceable<TypeParam>>::value);
141 TYPED_TEST(ReplaceableStaticAttributeTest, nothrow_destructible) {
143 std::is_nothrow_destructible<TypeParam>::value,
144 std::is_nothrow_destructible<Replaceable<TypeParam>>::value);
146 TYPED_TEST(ReplaceableStaticAttributeTest, nothrow_default_constructible) {
148 std::is_nothrow_default_constructible<TypeParam>::value,
149 std::is_nothrow_default_constructible<Replaceable<TypeParam>>::value);
151 TYPED_TEST(ReplaceableStaticAttributeTest, nothrow_move_constructible) {
153 std::is_nothrow_move_constructible<TypeParam>::value,
154 std::is_nothrow_move_constructible<Replaceable<TypeParam>>::value);
156 TYPED_TEST(ReplaceableStaticAttributeTest, nothrow_copy_constructible) {
158 std::is_nothrow_copy_constructible<TypeParam>::value,
159 std::is_nothrow_copy_constructible<Replaceable<TypeParam>>::value);
161 TYPED_TEST(ReplaceableStaticAttributeTest, nothrow_move_assignable) {
163 std::is_nothrow_destructible<TypeParam>::value &&
164 std::is_nothrow_copy_constructible<TypeParam>::value,
165 std::is_nothrow_move_assignable<Replaceable<TypeParam>>::value);
167 TYPED_TEST(ReplaceableStaticAttributeTest, nothrow_copy_assignable) {
169 std::is_nothrow_destructible<TypeParam>::value &&
170 std::is_nothrow_copy_constructible<TypeParam>::value,
171 std::is_nothrow_copy_assignable<Replaceable<TypeParam>>::value);
173 TYPED_TEST(ReplaceableStaticAttributeTest, replaceable) {
174 EXPECT_FALSE(is_replaceable<TypeParam>::value);
175 EXPECT_TRUE(is_replaceable<Replaceable<TypeParam>>::value);
178 TYPED_TEST(ReplaceableStaticAttributePairTest, copy_construct) {
179 using T = typename TypeParam::first_type;
180 using U = typename TypeParam::second_type;
182 (std::is_constructible<T, U const&>::value),
183 (std::is_constructible<Replaceable<T>, Replaceable<U> const&>::value));
185 TYPED_TEST(ReplaceableStaticAttributePairTest, move_construct) {
186 using T = typename TypeParam::first_type;
187 using U = typename TypeParam::second_type;
189 (std::is_constructible<T, U&&>::value),
190 (std::is_constructible<Replaceable<T>, Replaceable<U>&&>::value));
192 TYPED_TEST(ReplaceableStaticAttributePairTest, copy_assign) {
193 using T = typename TypeParam::first_type;
194 using U = typename TypeParam::second_type;
196 (std::is_convertible<U, T>::value && std::is_destructible<T>::value &&
197 std::is_copy_constructible<T>::value),
198 (std::is_assignable<Replaceable<T>, Replaceable<U> const&>::value));
200 TYPED_TEST(ReplaceableStaticAttributePairTest, move_assign) {
201 using T = typename TypeParam::first_type;
202 using U = typename TypeParam::second_type;
204 (std::is_convertible<U, T>::value && std::is_destructible<T>::value &&
205 std::is_move_constructible<T>::value),
206 (std::is_assignable<Replaceable<T>, Replaceable<U>&&>::value));
208 TYPED_TEST(ReplaceableStaticAttributePairTest, nothrow_copy_construct) {
209 using T = typename TypeParam::first_type;
210 using U = typename TypeParam::second_type;
212 (std::is_nothrow_constructible<T, U const&>::value &&
213 std::is_nothrow_destructible<T>::value),
214 (std::is_nothrow_constructible<Replaceable<T>, Replaceable<U> const&>::
217 TYPED_TEST(ReplaceableStaticAttributePairTest, nothrow_move_construct) {
218 using T = typename TypeParam::first_type;
219 using U = typename TypeParam::second_type;
221 (std::is_nothrow_constructible<T, U&&>::value &&
222 std::is_nothrow_destructible<T>::value),
223 (std::is_nothrow_constructible<Replaceable<T>, Replaceable<U>&&>::value));
225 TYPED_TEST(ReplaceableStaticAttributePairTest, nothrow_copy_assign) {
226 using T = typename TypeParam::first_type;
227 using U = typename TypeParam::second_type;
229 (std::is_nothrow_constructible<T, U const&>::value &&
230 std::is_nothrow_destructible<T>::value),
231 (std::is_nothrow_assignable<Replaceable<T>, Replaceable<U> const&>::
234 TYPED_TEST(ReplaceableStaticAttributePairTest, nothrow_move_assign) {
235 using T = typename TypeParam::first_type;
236 using U = typename TypeParam::second_type;
238 (std::is_nothrow_constructible<T, U&&>::value &&
239 std::is_nothrow_destructible<T>::value),
240 (std::is_nothrow_assignable<Replaceable<T>, Replaceable<U>&&>::value));
243 TEST(ReplaceableTest, Basics) {
244 auto rHasConstA = make_replaceable<HasConst>();
245 auto rHasConstB = make_replaceable<HasConst>(false);
246 EXPECT_TRUE(rHasConstA->b1);
247 EXPECT_FALSE(rHasConstB->b1);
248 rHasConstA = rHasConstB;
249 EXPECT_FALSE(rHasConstA->b1);
250 EXPECT_FALSE(rHasConstB->b1);
251 rHasConstB.emplace(true);
252 EXPECT_FALSE(rHasConstA->b1);
253 EXPECT_TRUE(rHasConstB->b1);
254 rHasConstA = std::move(rHasConstB);
255 EXPECT_TRUE(rHasConstA->b1);
256 EXPECT_TRUE(rHasConstB->b1);
259 TEST(ReplaceableTest, Constructors) {
262 auto rBasicCopy1 = Replaceable<Basic>(b);
263 auto rBasicMove1 = Replaceable<Basic>(std::move(b));
264 // From existing `Replaceable<T>`
265 auto rBasicCopy2 = Replaceable<Basic>(rBasicCopy1);
266 auto rBasicMove2 = Replaceable<Basic>(std::move(rBasicMove1));
271 TEST(ReplaceableTest, DestructsWhenExpected) {
274 Replaceable<HasRef> rHasRefA{i};
275 Replaceable<HasRef> rHasRefB{i};
281 rHasRefA = std::move(rHasRefB);
287 TEST(ReplaceableTest, Conversions) {
288 Replaceable<OddB> rOddB{in_place, {1, 2, 3}, 4};
289 Replaceable<OddA> rOddA{std::move(rOddB)};
290 Replaceable<OddB> rOddB2{rOddA};