2 * Copyright 2016 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;
30 struct T1 {}; // old-style IsRelocatable, below
31 struct T2 {}; // old-style IsRelocatable, below
32 struct T3 { typedef std::true_type IsRelocatable; };
33 struct T4 { typedef std::true_type IsTriviallyCopyable; };
37 struct F2 { typedef int IsRelocatable; };
38 struct F3 : T3 { typedef std::false_type IsRelocatable; };
42 template <> struct IsRelocatable<T1> : std::true_type {};
43 template <> FOLLY_ASSUME_RELOCATABLE(T2);
46 TEST(Traits, scalars) {
47 EXPECT_TRUE(IsRelocatable<int>::value);
48 EXPECT_TRUE(IsRelocatable<bool>::value);
49 EXPECT_TRUE(IsRelocatable<double>::value);
50 EXPECT_TRUE(IsRelocatable<void*>::value);
53 TEST(Traits, containers) {
54 EXPECT_TRUE (IsRelocatable<vector<F1>>::value);
55 EXPECT_TRUE((IsRelocatable<pair<F1, F1>>::value));
56 EXPECT_TRUE ((IsRelocatable<pair<T1, T2>>::value));
59 TEST(Traits, original) {
60 EXPECT_TRUE(IsRelocatable<T1>::value);
61 EXPECT_TRUE(IsRelocatable<T2>::value);
64 TEST(Traits, typedefd) {
65 EXPECT_TRUE (IsRelocatable<T3>::value);
66 EXPECT_TRUE (IsRelocatable<T5>::value);
67 EXPECT_FALSE(IsRelocatable<F2>::value);
68 EXPECT_FALSE(IsRelocatable<F3>::value);
72 EXPECT_TRUE(IsRelocatable<F1>::value);
73 EXPECT_TRUE(IsRelocatable<F4>::value);
76 TEST(Traits, bitprop) {
77 EXPECT_TRUE(IsTriviallyCopyable<T4>::value);
78 EXPECT_TRUE(IsRelocatable<T4>::value);
81 TEST(Traits, bitAndInit) {
82 EXPECT_TRUE (IsTriviallyCopyable<int>::value);
83 EXPECT_FALSE(IsTriviallyCopyable<vector<int>>::value);
84 EXPECT_TRUE (IsZeroInitializable<int>::value);
85 EXPECT_FALSE(IsZeroInitializable<vector<int>>::value);
88 TEST(Trait, logicOperators) {
89 static_assert(Conjunction<true_type>::value, "");
90 static_assert(!Conjunction<false_type>::value, "");
91 static_assert(is_same<Conjunction<true_type>::type, true_type>::value, "");
92 static_assert(is_same<Conjunction<false_type>::type, false_type>::value, "");
93 static_assert(Conjunction<true_type, true_type>::value, "");
94 static_assert(!Conjunction<true_type, false_type>::value, "");
96 static_assert(Disjunction<true_type>::value, "");
97 static_assert(!Disjunction<false_type>::value, "");
98 static_assert(is_same<Disjunction<true_type>::type, true_type>::value, "");
99 static_assert(is_same<Disjunction<false_type>::type, false_type>::value, "");
100 static_assert(Disjunction<true_type, true_type>::value, "");
101 static_assert(Disjunction<true_type, false_type>::value, "");
103 static_assert(!Negation<true_type>::value, "");
104 static_assert(Negation<false_type>::value, "");
107 TEST(Traits, is_negative) {
108 EXPECT_TRUE(folly::is_negative(-1));
109 EXPECT_FALSE(folly::is_negative(0));
110 EXPECT_FALSE(folly::is_negative(1));
111 EXPECT_FALSE(folly::is_negative(0u));
112 EXPECT_FALSE(folly::is_negative(1u));
114 EXPECT_TRUE(folly::is_non_positive(-1));
115 EXPECT_TRUE(folly::is_non_positive(0));
116 EXPECT_FALSE(folly::is_non_positive(1));
117 EXPECT_TRUE(folly::is_non_positive(0u));
118 EXPECT_FALSE(folly::is_non_positive(1u));
121 TEST(Traits, relational) {
122 // We test, especially, the edge cases to make sure we don't
123 // trip -Wtautological-comparisons
125 EXPECT_FALSE((folly::less_than<uint8_t, 0u, uint8_t>(0u)));
126 EXPECT_FALSE((folly::less_than<uint8_t, 0u, uint8_t>(254u)));
127 EXPECT_FALSE((folly::less_than<uint8_t, 255u, uint8_t>(255u)));
128 EXPECT_TRUE( (folly::less_than<uint8_t, 255u, uint8_t>(254u)));
130 EXPECT_FALSE((folly::greater_than<uint8_t, 0u, uint8_t>(0u)));
131 EXPECT_TRUE( (folly::greater_than<uint8_t, 0u, uint8_t>(254u)));
132 EXPECT_FALSE((folly::greater_than<uint8_t, 255u, uint8_t>(255u)));
133 EXPECT_FALSE((folly::greater_than<uint8_t, 255u, uint8_t>(254u)));
136 #if FOLLY_HAVE_INT128_T
138 TEST(Traits, int128) {
140 (::std::is_same<::std::make_unsigned<__int128_t>::type, __uint128_t>::
143 ::std::is_same<::std::make_signed<__int128_t>::type, __int128_t>::value));
145 (::std::is_same<::std::make_unsigned<__uint128_t>::type, __uint128_t>::
148 (::std::is_same<::std::make_signed<__uint128_t>::type, __int128_t>::
150 EXPECT_TRUE((::std::is_arithmetic<__int128_t>::value));
151 EXPECT_TRUE((::std::is_arithmetic<__uint128_t>::value));
152 EXPECT_TRUE((::std::is_integral<__int128_t>::value));
153 EXPECT_TRUE((::std::is_integral<__uint128_t>::value));
154 EXPECT_FALSE((::std::is_unsigned<__int128_t>::value));
155 EXPECT_TRUE((::std::is_signed<__int128_t>::value));
156 EXPECT_TRUE((::std::is_unsigned<__uint128_t>::value));
157 EXPECT_FALSE((::std::is_signed<__uint128_t>::value));
158 EXPECT_TRUE((::std::is_fundamental<__int128_t>::value));
159 EXPECT_TRUE((::std::is_fundamental<__uint128_t>::value));
160 EXPECT_TRUE((::std::is_scalar<__int128_t>::value));
161 EXPECT_TRUE((::std::is_scalar<__uint128_t>::value));
164 #endif // FOLLY_HAVE_INT128_T
166 template <typename T, typename... Args>
167 void testIsRelocatable(Args&&... args) {
168 if (!IsRelocatable<T>::value) return;
170 // We use placement new on zeroed memory to avoid garbage subsections
171 char vsrc[sizeof(T)] = { 0 };
172 char vdst[sizeof(T)] = { 0 };
173 char vcpy[sizeof(T)];
175 T* src = new (vsrc) T(std::forward<Args>(args)...);
176 SCOPE_EXIT { src->~T(); };
177 std::memcpy(vcpy, vsrc, sizeof(T));
179 T* dst = new (vdst) T(std::move(*src));
180 SCOPE_EXIT { dst->~T(); };
182 EXPECT_EQ(deep, *dst);
183 #pragma GCC diagnostic push
184 #pragma GCC diagnostic ignored "-Wstrict-aliasing"
185 EXPECT_EQ(deep, *reinterpret_cast<T*>(vcpy));
186 #pragma GCC diagnostic pop
188 // This test could technically fail; however, this is what relocation
189 // almost always means, so it's a good test to have
190 EXPECT_EQ(std::memcmp(vcpy, vdst, sizeof(T)), 0);
193 TEST(Traits, actuallyRelocatable) {
194 // Ensure that we test stack and heap allocation for strings with in-situ
196 testIsRelocatable<std::string>("1");
197 testIsRelocatable<std::string>(sizeof(std::string) + 1, 'x');
199 testIsRelocatable<std::vector<char>>(5, 'g');
202 struct membership_no {};
203 struct membership_yes { using x = void; };
204 FOLLY_CREATE_HAS_MEMBER_TYPE_TRAITS(has_member_type_x, x);
206 TEST(Traits, has_member_type) {
207 EXPECT_FALSE(bool(has_member_type_x<membership_no>::value));
208 EXPECT_TRUE(bool(has_member_type_x<membership_yes>::value));