1/*
2 * Copyright 2012-present Facebook, Inc.
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/Traits.h>
18
19#include <cstring>
20#include <string>
21#include <type_traits>
22#include <utility>
23
24#include <folly/ScopeGuard.h>
25#include <folly/portability/GTest.h>
26
27using namespace folly;
28using namespace std;
29
30namespace {
31
32FOLLY_CREATE_HAS_MEMBER_TYPE_TRAITS(has_member_type_x, x);
33} // namespace
34
35TEST(Traits, has_member_type) {
36 struct membership_no {};
37 struct membership_yes {
38 using x = void;
39 };
40
41 EXPECT_TRUE((is_same<false_type, has_member_type_x<membership_no>>::value));
42 EXPECT_TRUE((is_same<true_type, has_member_type_x<membership_yes>>::value));
43}
44
45// Note: FOLLY_CREATE_HAS_MEMBER_FN_TRAITS tests are in
46// folly/test/HasMemberFnTraitsTest.cpp.
47
48struct T1 {}; // old-style IsRelocatable, below
49struct T2 {}; // old-style IsRelocatable, below
50struct T3 {
51 typedef std::true_type IsRelocatable;
52};
53struct T5 : T3 {};
54
55struct F1 {};
56struct F2 {
57 typedef int IsRelocatable;
58};
59struct F3 : T3 {
60 typedef std::false_type IsRelocatable;
61};
62struct F4 : T1 {};
63
64namespace folly {
65template <>
66struct IsRelocatable<T1> : std::true_type {};
67template <>
68FOLLY_ASSUME_RELOCATABLE(T2);
69} // namespace folly
70
71TEST(Traits, scalars) {
72 EXPECT_TRUE(IsRelocatable<int>::value);
73 EXPECT_TRUE(IsRelocatable<bool>::value);
74 EXPECT_TRUE(IsRelocatable<double>::value);
75 EXPECT_TRUE(IsRelocatable<void*>::value);
76}
77
78TEST(Traits, containers) {
79 EXPECT_TRUE(IsRelocatable<vector<F1>>::value);
80 EXPECT_TRUE((IsRelocatable<pair<F1, F1>>::value));
81 EXPECT_TRUE((IsRelocatable<pair<T1, T2>>::value));
82}
83
84TEST(Traits, original) {
85 EXPECT_TRUE(IsRelocatable<T1>::value);
86 EXPECT_TRUE(IsRelocatable<T2>::value);
87}
88
89TEST(Traits, typedefd) {
90 EXPECT_TRUE(IsRelocatable<T3>::value);
91 EXPECT_TRUE(IsRelocatable<T5>::value);
92 EXPECT_FALSE(IsRelocatable<F2>::value);
93 EXPECT_FALSE(IsRelocatable<F3>::value);
94}
95
96TEST(Traits, unset) {
97 EXPECT_TRUE(IsRelocatable<F1>::value);
98 EXPECT_TRUE(IsRelocatable<F4>::value);
99}
100
101TEST(Traits, bitAndInit) {
102 EXPECT_TRUE(IsZeroInitializable<int>::value);
103 EXPECT_FALSE(IsZeroInitializable<vector<int>>::value);
104}
105
106TEST(Trait, logicOperators) {
107 static_assert(Conjunction<true_type>::value, "");
108 static_assert(!Conjunction<false_type>::value, "");
109 static_assert(is_same<Conjunction<true_type>::type, true_type>::value, "");
110 static_assert(is_same<Conjunction<false_type>::type, false_type>::value, "");
111 static_assert(Conjunction<true_type, true_type>::value, "");
112 static_assert(!Conjunction<true_type, false_type>::value, "");
113
114 static_assert(Disjunction<true_type>::value, "");
115 static_assert(!Disjunction<false_type>::value, "");
116 static_assert(is_same<Disjunction<true_type>::type, true_type>::value, "");
117 static_assert(is_same<Disjunction<false_type>::type, false_type>::value, "");
118 static_assert(Disjunction<true_type, true_type>::value, "");
119 static_assert(Disjunction<true_type, false_type>::value, "");
120
121 static_assert(!Negation<true_type>::value, "");
122 static_assert(Negation<false_type>::value, "");
123}
124
125TEST(Traits, is_negative) {
126 EXPECT_TRUE(folly::is_negative(-1));
127 EXPECT_FALSE(folly::is_negative(0));
128 EXPECT_FALSE(folly::is_negative(1));
129 EXPECT_FALSE(folly::is_negative(0u));
130 EXPECT_FALSE(folly::is_negative(1u));
131
132 EXPECT_TRUE(folly::is_non_positive(-1));
133 EXPECT_TRUE(folly::is_non_positive(0));
134 EXPECT_FALSE(folly::is_non_positive(1));
135 EXPECT_TRUE(folly::is_non_positive(0u));
136 EXPECT_FALSE(folly::is_non_positive(1u));
137}
138
139TEST(Traits, relational) {
140 // We test, especially, the edge cases to make sure we don't
141 // trip -Wtautological-comparisons
142
143 EXPECT_FALSE((folly::less_than<uint8_t, 0u, uint8_t>(0u)));
144 EXPECT_FALSE((folly::less_than<uint8_t, 0u, uint8_t>(254u)));
145 EXPECT_FALSE((folly::less_than<uint8_t, 255u, uint8_t>(255u)));
146 EXPECT_TRUE((folly::less_than<uint8_t, 255u, uint8_t>(254u)));
147
148 EXPECT_FALSE((folly::greater_than<uint8_t, 0u, uint8_t>(0u)));
149 EXPECT_TRUE((folly::greater_than<uint8_t, 0u, uint8_t>(254u)));
150 EXPECT_FALSE((folly::greater_than<uint8_t, 255u, uint8_t>(255u)));
151 EXPECT_FALSE((folly::greater_than<uint8_t, 255u, uint8_t>(254u)));
152}
153
154#if FOLLY_HAVE_INT128_T
155
156TEST(Traits, int128) {
157 EXPECT_TRUE(
158 (::std::is_same<::std::make_unsigned<__int128_t>::type, __uint128_t>::
159 value));
160 EXPECT_TRUE((
161 ::std::is_same<::std::make_signed<__int128_t>::type, __int128_t>::value));
162 EXPECT_TRUE(
163 (::std::is_same<::std::make_unsigned<__uint128_t>::type, __uint128_t>::
164 value));
165 EXPECT_TRUE(
166 (::std::is_same<::std::make_signed<__uint128_t>::type, __int128_t>::
167 value));
168 EXPECT_TRUE((::std::is_arithmetic<__int128_t>::value));
169 EXPECT_TRUE((::std::is_arithmetic<__uint128_t>::value));
170 EXPECT_TRUE((::std::is_integral<__int128_t>::value));
171 EXPECT_TRUE((::std::is_integral<__uint128_t>::value));
172 EXPECT_FALSE((::std::is_unsigned<__int128_t>::value));
173 EXPECT_TRUE((::std::is_signed<__int128_t>::value));
174 EXPECT_TRUE((::std::is_unsigned<__uint128_t>::value));
175 EXPECT_FALSE((::std::is_signed<__uint128_t>::value));
176 EXPECT_TRUE((::std::is_fundamental<__int128_t>::value));
177 EXPECT_TRUE((::std::is_fundamental<__uint128_t>::value));
178 EXPECT_TRUE((::std::is_scalar<__int128_t>::value));
179 EXPECT_TRUE((::std::is_scalar<__uint128_t>::value));
180}
181
182#endif // FOLLY_HAVE_INT128_T
183
184template <typename T, typename... Args>
185void testIsRelocatable(Args&&... args) {
186 if (!IsRelocatable<T>::value) {
187 return;
188 }
189
190 // We use placement new on zeroed memory to avoid garbage subsections
191 char vsrc[sizeof(T)] = {0};
192 char vdst[sizeof(T)] = {0};
193 char vcpy[sizeof(T)];
194
195 T* src = new (vsrc) T(std::forward<Args>(args)...);
196 SCOPE_EXIT {
197 src->~T();
198 };
199 std::memcpy(vcpy, vsrc, sizeof(T));
200 T deep(*src);
201 T* dst = new (vdst) T(std::move(*src));
202 SCOPE_EXIT {
203 dst->~T();
204 };
205
206 EXPECT_EQ(deep, *dst);
207#pragma GCC diagnostic push
208#pragma GCC diagnostic ignored "-Wstrict-aliasing"
209 EXPECT_EQ(deep, *reinterpret_cast<T*>(vcpy));
210#pragma GCC diagnostic pop
211
212 // This test could technically fail; however, this is what relocation
213 // almost always means, so it's a good test to have
214 EXPECT_EQ(std::memcmp(vcpy, vdst, sizeof(T)), 0);
215}
216
217TEST(Traits, actuallyRelocatable) {
218 // Ensure that we test stack and heap allocation for strings with in-situ
219 // capacity
220 testIsRelocatable<std::string>("1");
221 testIsRelocatable<std::string>(sizeof(std::string) + 1, 'x');
222
223 testIsRelocatable<std::vector<char>>(5, 'g');
224}
225
226namespace {
227// has_value_type<T>::value is true if T has a nested type `value_type`
228template <class T, class = void>
229struct has_value_type : std::false_type {};
230
231template <class T>
232struct has_value_type<T, folly::void_t<typename T::value_type>>
233 : std::true_type {};
234
235struct some_tag {};
236
237template <typename T>
238struct container {
239 template <class... Args>
240 container(
241 folly::type_t<some_tag, decltype(T(std::declval<Args>()...))>,
242 Args&&...) {}
243};
244} // namespace
245
246TEST(Traits, void_t) {
247 EXPECT_TRUE((::std::is_same<folly::void_t<>, void>::value));
248 EXPECT_TRUE((::std::is_same<folly::void_t<int>, void>::value));
249 EXPECT_TRUE((::std::is_same<folly::void_t<int, short>, void>::value));
250 EXPECT_TRUE(
251 (::std::is_same<folly::void_t<int, short, std::string>, void>::value));
252 EXPECT_TRUE((::has_value_type<std::string>::value));
253 EXPECT_FALSE((::has_value_type<int>::value));
254}
255
256TEST(Traits, type_t) {
257 EXPECT_TRUE((::std::is_same<folly::type_t<float>, float>::value));
258 EXPECT_TRUE((::std::is_same<folly::type_t<float, int>, float>::value));
259 EXPECT_TRUE((::std::is_same<folly::type_t<float, int, short>, float>::value));
260 EXPECT_TRUE(
261 (::std::is_same<folly::type_t<float, int, short, std::string>, float>::
262 value));
263 EXPECT_TRUE((
264 ::std::is_constructible<::container<std::string>, some_tag, std::string>::
265 value));
266 EXPECT_FALSE(
267 (::std::is_constructible<::container<std::string>, some_tag, float>::
268 value));
269}
270
271TEST(Traits, aligned_storage_for_t) {
272 struct alignas(2) Foo {
273 char data[4];
274 };
275 using storage = aligned_storage_for_t<Foo[4]>;
276 EXPECT_EQ(16, sizeof(storage));
277 EXPECT_EQ(2, alignof(storage));
278 EXPECT_TRUE(std::is_trivial<storage>::value);
279 EXPECT_TRUE(std::is_standard_layout<storage>::value);
280 EXPECT_TRUE(std::is_pod<storage>::value); // pod = trivial + standard-layout
281}
282
283TEST(Traits, remove_cvref) {
284 using folly::remove_cvref;
285 using folly::remove_cvref_t;
286
287 // test all possible c-ref qualifiers without volatile
288 EXPECT_TRUE((std::is_same<remove_cvref_t<int>, int>::value));
289 EXPECT_TRUE((std::is_same<remove_cvref<int>::type, int>::value));
290
291 EXPECT_TRUE((std::is_same<remove_cvref_t<int&&>, int>::value));
292 EXPECT_TRUE((std::is_same<remove_cvref<int&&>::type, int>::value));
293
294 EXPECT_TRUE((std::is_same<remove_cvref_t<int&>, int>::value));
295 EXPECT_TRUE((std::is_same<remove_cvref<int&>::type, int>::value));
296
297 EXPECT_TRUE((std::is_same<remove_cvref_t<int const>, int>::value));
298 EXPECT_TRUE((std::is_same<remove_cvref<int const>::type, int>::value));
299
300 EXPECT_TRUE((std::is_same<remove_cvref_t<int const&>, int>::value));
301 EXPECT_TRUE((std::is_same<remove_cvref<int const&>::type, int>::value));
302
303 EXPECT_TRUE((std::is_same<remove_cvref_t<int const&&>, int>::value));
304 EXPECT_TRUE((std::is_same<remove_cvref<int const&&>::type, int>::value));
305
306 // test all possible c-ref qualifiers with volatile
307 EXPECT_TRUE((std::is_same<remove_cvref_t<int volatile>, int>::value));
308 EXPECT_TRUE((std::is_same<remove_cvref<int volatile>::type, int>::value));
309
310 EXPECT_TRUE((std::is_same<remove_cvref_t<int volatile&&>, int>::value));
311 EXPECT_TRUE((std::is_same<remove_cvref<int volatile&&>::type, int>::value));
312
313 EXPECT_TRUE((std::is_same<remove_cvref_t<int volatile&>, int>::value));
314 EXPECT_TRUE((std::is_same<remove_cvref<int volatile&>::type, int>::value));
315
316 EXPECT_TRUE((std::is_same<remove_cvref_t<int volatile const>, int>::value));
317 EXPECT_TRUE(
318 (std::is_same<remove_cvref<int volatile const>::type, int>::value));
319
320 EXPECT_TRUE((std::is_same<remove_cvref_t<int volatile const&>, int>::value));
321 EXPECT_TRUE(
322 (std::is_same<remove_cvref<int volatile const&>::type, int>::value));
323
324 EXPECT_TRUE((std::is_same<remove_cvref_t<int volatile const&&>, int>::value));
325 EXPECT_TRUE(
326 (std::is_same<remove_cvref<int volatile const&&>::type, int>::value));
327}
328
329TEST(Traits, like) {
330 EXPECT_TRUE((std::is_same<like_t<int, char>, char>::value));
331 EXPECT_TRUE((std::is_same<like_t<int const, char>, char const>::value));
332 EXPECT_TRUE((std::is_same<like_t<int volatile, char>, char volatile>::value));
333 EXPECT_TRUE(
334 (std::is_same<like_t<int const volatile, char>, char const volatile>::
335 value));
336 EXPECT_TRUE((std::is_same<like_t<int&, char>, char&>::value));
337 EXPECT_TRUE((std::is_same<like_t<int const&, char>, char const&>::value));
338 EXPECT_TRUE(
339 (std::is_same<like_t<int volatile&, char>, char volatile&>::value));
340 EXPECT_TRUE(
341 (std::is_same<like_t<int const volatile&, char>, char const volatile&>::
342 value));
343 EXPECT_TRUE((std::is_same<like_t<int&&, char>, char&&>::value));
344 EXPECT_TRUE((std::is_same<like_t<int const&&, char>, char const&&>::value));
345 EXPECT_TRUE(
346 (std::is_same<like_t<int volatile&&, char>, char volatile&&>::value));
347 EXPECT_TRUE(
348 (std::is_same<like_t<int const volatile&&, char>, char const volatile&&>::
349 value));
350}
351