2 * Copyright 2017 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/Traits.h>
21 #include <type_traits>
24 #include <folly/ScopeGuard.h>
25 #include <folly/portability/GTest.h>
27 using namespace folly;
32 FOLLY_CREATE_HAS_MEMBER_TYPE_TRAITS(has_member_type_x, x);
35 TEST(Traits, has_member_type) {
36 struct membership_no {};
37 struct membership_yes {
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));
45 // Note: FOLLY_CREATE_HAS_MEMBER_FN_TRAITS tests are in
46 // folly/test/HasMemberFnTraitsTest.cpp.
48 struct T1 {}; // old-style IsRelocatable, below
49 struct T2 {}; // old-style IsRelocatable, below
50 struct T3 { typedef std::true_type IsRelocatable; };
51 struct T4 { typedef std::true_type IsTriviallyCopyable; };
55 struct F2 { typedef int IsRelocatable; };
56 struct F3 : T3 { typedef std::false_type IsRelocatable; };
61 struct IsRelocatable<T1> : std::true_type {};
63 FOLLY_ASSUME_RELOCATABLE(T2);
66 TEST(Traits, scalars) {
67 EXPECT_TRUE(IsRelocatable<int>::value);
68 EXPECT_TRUE(IsRelocatable<bool>::value);
69 EXPECT_TRUE(IsRelocatable<double>::value);
70 EXPECT_TRUE(IsRelocatable<void*>::value);
73 TEST(Traits, containers) {
74 EXPECT_TRUE (IsRelocatable<vector<F1>>::value);
75 EXPECT_TRUE((IsRelocatable<pair<F1, F1>>::value));
76 EXPECT_TRUE ((IsRelocatable<pair<T1, T2>>::value));
79 TEST(Traits, original) {
80 EXPECT_TRUE(IsRelocatable<T1>::value);
81 EXPECT_TRUE(IsRelocatable<T2>::value);
84 TEST(Traits, typedefd) {
85 EXPECT_TRUE (IsRelocatable<T3>::value);
86 EXPECT_TRUE (IsRelocatable<T5>::value);
87 EXPECT_FALSE(IsRelocatable<F2>::value);
88 EXPECT_FALSE(IsRelocatable<F3>::value);
92 EXPECT_TRUE(IsRelocatable<F1>::value);
93 EXPECT_TRUE(IsRelocatable<F4>::value);
96 TEST(Traits, bitprop) {
97 EXPECT_TRUE(IsTriviallyCopyable<T4>::value);
98 EXPECT_TRUE(IsRelocatable<T4>::value);
101 TEST(Traits, bitAndInit) {
102 EXPECT_TRUE (IsTriviallyCopyable<int>::value);
103 EXPECT_FALSE(IsTriviallyCopyable<vector<int>>::value);
104 EXPECT_TRUE (IsZeroInitializable<int>::value);
105 EXPECT_FALSE(IsZeroInitializable<vector<int>>::value);
108 TEST(Trait, logicOperators) {
109 static_assert(Conjunction<true_type>::value, "");
110 static_assert(!Conjunction<false_type>::value, "");
111 static_assert(is_same<Conjunction<true_type>::type, true_type>::value, "");
112 static_assert(is_same<Conjunction<false_type>::type, false_type>::value, "");
113 static_assert(Conjunction<true_type, true_type>::value, "");
114 static_assert(!Conjunction<true_type, false_type>::value, "");
116 static_assert(Disjunction<true_type>::value, "");
117 static_assert(!Disjunction<false_type>::value, "");
118 static_assert(is_same<Disjunction<true_type>::type, true_type>::value, "");
119 static_assert(is_same<Disjunction<false_type>::type, false_type>::value, "");
120 static_assert(Disjunction<true_type, true_type>::value, "");
121 static_assert(Disjunction<true_type, false_type>::value, "");
123 static_assert(!Negation<true_type>::value, "");
124 static_assert(Negation<false_type>::value, "");
127 TEST(Traits, is_negative) {
128 EXPECT_TRUE(folly::is_negative(-1));
129 EXPECT_FALSE(folly::is_negative(0));
130 EXPECT_FALSE(folly::is_negative(1));
131 EXPECT_FALSE(folly::is_negative(0u));
132 EXPECT_FALSE(folly::is_negative(1u));
134 EXPECT_TRUE(folly::is_non_positive(-1));
135 EXPECT_TRUE(folly::is_non_positive(0));
136 EXPECT_FALSE(folly::is_non_positive(1));
137 EXPECT_TRUE(folly::is_non_positive(0u));
138 EXPECT_FALSE(folly::is_non_positive(1u));
141 TEST(Traits, relational) {
142 // We test, especially, the edge cases to make sure we don't
143 // trip -Wtautological-comparisons
145 EXPECT_FALSE((folly::less_than<uint8_t, 0u, uint8_t>(0u)));
146 EXPECT_FALSE((folly::less_than<uint8_t, 0u, uint8_t>(254u)));
147 EXPECT_FALSE((folly::less_than<uint8_t, 255u, uint8_t>(255u)));
148 EXPECT_TRUE( (folly::less_than<uint8_t, 255u, uint8_t>(254u)));
150 EXPECT_FALSE((folly::greater_than<uint8_t, 0u, uint8_t>(0u)));
151 EXPECT_TRUE( (folly::greater_than<uint8_t, 0u, uint8_t>(254u)));
152 EXPECT_FALSE((folly::greater_than<uint8_t, 255u, uint8_t>(255u)));
153 EXPECT_FALSE((folly::greater_than<uint8_t, 255u, uint8_t>(254u)));
156 #if FOLLY_HAVE_INT128_T
158 TEST(Traits, int128) {
160 (::std::is_same<::std::make_unsigned<__int128_t>::type, __uint128_t>::
163 ::std::is_same<::std::make_signed<__int128_t>::type, __int128_t>::value));
165 (::std::is_same<::std::make_unsigned<__uint128_t>::type, __uint128_t>::
168 (::std::is_same<::std::make_signed<__uint128_t>::type, __int128_t>::
170 EXPECT_TRUE((::std::is_arithmetic<__int128_t>::value));
171 EXPECT_TRUE((::std::is_arithmetic<__uint128_t>::value));
172 EXPECT_TRUE((::std::is_integral<__int128_t>::value));
173 EXPECT_TRUE((::std::is_integral<__uint128_t>::value));
174 EXPECT_FALSE((::std::is_unsigned<__int128_t>::value));
175 EXPECT_TRUE((::std::is_signed<__int128_t>::value));
176 EXPECT_TRUE((::std::is_unsigned<__uint128_t>::value));
177 EXPECT_FALSE((::std::is_signed<__uint128_t>::value));
178 EXPECT_TRUE((::std::is_fundamental<__int128_t>::value));
179 EXPECT_TRUE((::std::is_fundamental<__uint128_t>::value));
180 EXPECT_TRUE((::std::is_scalar<__int128_t>::value));
181 EXPECT_TRUE((::std::is_scalar<__uint128_t>::value));
184 #endif // FOLLY_HAVE_INT128_T
186 template <typename T, typename... Args>
187 void testIsRelocatable(Args&&... args) {
188 if (!IsRelocatable<T>::value) {
192 // We use placement new on zeroed memory to avoid garbage subsections
193 char vsrc[sizeof(T)] = { 0 };
194 char vdst[sizeof(T)] = { 0 };
195 char vcpy[sizeof(T)];
197 T* src = new (vsrc) T(std::forward<Args>(args)...);
198 SCOPE_EXIT { src->~T(); };
199 std::memcpy(vcpy, vsrc, sizeof(T));
201 T* dst = new (vdst) T(std::move(*src));
202 SCOPE_EXIT { dst->~T(); };
204 EXPECT_EQ(deep, *dst);
205 #pragma GCC diagnostic push
206 #pragma GCC diagnostic ignored "-Wstrict-aliasing"
207 EXPECT_EQ(deep, *reinterpret_cast<T*>(vcpy));
208 #pragma GCC diagnostic pop
210 // This test could technically fail; however, this is what relocation
211 // almost always means, so it's a good test to have
212 EXPECT_EQ(std::memcmp(vcpy, vdst, sizeof(T)), 0);
215 TEST(Traits, actuallyRelocatable) {
216 // Ensure that we test stack and heap allocation for strings with in-situ
218 testIsRelocatable<std::string>("1");
219 testIsRelocatable<std::string>(sizeof(std::string) + 1, 'x');
221 testIsRelocatable<std::vector<char>>(5, 'g');
225 // has_value_type<T>::value is true if T has a nested type `value_type`
226 template <class T, class = void>
227 struct has_value_type : std::false_type {};
230 struct has_value_type<T, folly::void_t<typename T::value_type>>
235 template <typename T>
237 template <class... Args>
239 folly::type_t<some_tag, decltype(T(std::declval<Args>()...))>,
244 TEST(Traits, void_t) {
245 EXPECT_TRUE((::std::is_same<folly::void_t<>, void>::value));
246 EXPECT_TRUE((::std::is_same<folly::void_t<int>, void>::value));
247 EXPECT_TRUE((::std::is_same<folly::void_t<int, short>, void>::value));
249 (::std::is_same<folly::void_t<int, short, std::string>, void>::value));
250 EXPECT_TRUE((::has_value_type<std::string>::value));
251 EXPECT_FALSE((::has_value_type<int>::value));
254 TEST(Traits, type_t) {
255 EXPECT_TRUE((::std::is_same<folly::type_t<float>, float>::value));
256 EXPECT_TRUE((::std::is_same<folly::type_t<float, int>, float>::value));
257 EXPECT_TRUE((::std::is_same<folly::type_t<float, int, short>, float>::value));
259 (::std::is_same<folly::type_t<float, int, short, std::string>, float>::
262 ::std::is_constructible<::container<std::string>, some_tag, std::string>::
265 (::std::is_constructible<::container<std::string>, some_tag, float>::
269 TEST(Traits, remove_cvref) {
270 using folly::remove_cvref;
271 using folly::remove_cvref_t;
273 // test all possible c-ref qualifiers without volatile
274 EXPECT_TRUE((std::is_same<remove_cvref_t<int>, int>::value));
275 EXPECT_TRUE((std::is_same<remove_cvref<int>::type, int>::value));
277 EXPECT_TRUE((std::is_same<remove_cvref_t<int&&>, int>::value));
278 EXPECT_TRUE((std::is_same<remove_cvref<int&&>::type, int>::value));
280 EXPECT_TRUE((std::is_same<remove_cvref_t<int&>, int>::value));
281 EXPECT_TRUE((std::is_same<remove_cvref<int&>::type, int>::value));
283 EXPECT_TRUE((std::is_same<remove_cvref_t<int const>, int>::value));
284 EXPECT_TRUE((std::is_same<remove_cvref<int const>::type, int>::value));
286 EXPECT_TRUE((std::is_same<remove_cvref_t<int const&>, int>::value));
287 EXPECT_TRUE((std::is_same<remove_cvref<int const&>::type, int>::value));
289 EXPECT_TRUE((std::is_same<remove_cvref_t<int const&&>, int>::value));
290 EXPECT_TRUE((std::is_same<remove_cvref<int const&&>::type, int>::value));
292 // test all possible c-ref qualifiers with volatile
293 EXPECT_TRUE((std::is_same<remove_cvref_t<int volatile>, int>::value));
294 EXPECT_TRUE((std::is_same<remove_cvref<int volatile>::type, int>::value));
296 EXPECT_TRUE((std::is_same<remove_cvref_t<int volatile&&>, int>::value));
297 EXPECT_TRUE((std::is_same<remove_cvref<int volatile&&>::type, int>::value));
299 EXPECT_TRUE((std::is_same<remove_cvref_t<int volatile&>, int>::value));
300 EXPECT_TRUE((std::is_same<remove_cvref<int volatile&>::type, int>::value));
302 EXPECT_TRUE((std::is_same<remove_cvref_t<int volatile const>, int>::value));
304 (std::is_same<remove_cvref<int volatile const>::type, int>::value));
306 EXPECT_TRUE((std::is_same<remove_cvref_t<int volatile const&>, int>::value));
308 (std::is_same<remove_cvref<int volatile const&>::type, int>::value));
310 EXPECT_TRUE((std::is_same<remove_cvref_t<int volatile const&&>, int>::value));
312 (std::is_same<remove_cvref<int volatile const&&>::type, int>::value));