Add make_array to folly
[folly.git] / folly / test / TraitsTest.cpp
1 /*
2  * Copyright 2016 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 <gtest/gtest.h>
26
27 using namespace folly;
28 using namespace std;
29
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; };
34 struct T5 : T3 {};
35
36 struct F1 {};
37 struct F2 { typedef int IsRelocatable; };
38 struct F3 : T3 { typedef std::false_type IsRelocatable; };
39 struct F4 : T1 {};
40
41 namespace folly {
42   template <> struct IsRelocatable<T1> : std::true_type {};
43   template <> FOLLY_ASSUME_RELOCATABLE(T2);
44 }
45
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);
51 }
52
53 TEST(Traits, containers) {
54   EXPECT_TRUE  (IsRelocatable<vector<F1>>::value);
55   EXPECT_FALSE((IsRelocatable<pair<F1, F1>>::value));
56   EXPECT_TRUE ((IsRelocatable<pair<T1, T2>>::value));
57 }
58
59 TEST(Traits, original) {
60   EXPECT_TRUE(IsRelocatable<T1>::value);
61   EXPECT_TRUE(IsRelocatable<T2>::value);
62 }
63
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);
69 }
70
71 TEST(Traits, unset) {
72   EXPECT_FALSE(IsRelocatable<F1>::value);
73   EXPECT_FALSE(IsRelocatable<F4>::value);
74 }
75
76 TEST(Traits, bitprop) {
77   EXPECT_TRUE(IsTriviallyCopyable<T4>::value);
78   EXPECT_TRUE(IsRelocatable<T4>::value);
79 }
80
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);
86 }
87
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, "");
95
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, "");
102
103   static_assert(!Negation<true_type>::value, "");
104   static_assert(Negation<false_type>::value, "");
105 }
106
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));
113
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));
119 }
120
121 TEST(Traits, relational) {
122   // We test, especially, the edge cases to make sure we don't
123   // trip -Wtautological-comparisons
124
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)));
129
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)));
134 }
135
136 template <typename T, typename... Args>
137 void testIsRelocatable(Args&&... args) {
138   if (!IsRelocatable<T>::value) return;
139
140   // We use placement new on zeroed memory to avoid garbage subsections
141   char vsrc[sizeof(T)] = { 0 };
142   char vdst[sizeof(T)] = { 0 };
143   char vcpy[sizeof(T)];
144
145   T* src = new (vsrc) T(std::forward<Args>(args)...);
146   SCOPE_EXIT { src->~T(); };
147   std::memcpy(vcpy, vsrc, sizeof(T));
148   T deep(*src);
149   T* dst = new (vdst) T(std::move(*src));
150   SCOPE_EXIT { dst->~T(); };
151
152   EXPECT_EQ(deep, *dst);
153 #pragma GCC diagnostic push
154 #pragma GCC diagnostic ignored "-Wstrict-aliasing"
155   EXPECT_EQ(deep, *reinterpret_cast<T*>(vcpy));
156 #pragma GCC diagnostic pop
157
158   // This test could technically fail; however, this is what relocation
159   // almost always means, so it's a good test to have
160   EXPECT_EQ(std::memcmp(vcpy, vdst, sizeof(T)), 0);
161 }
162
163 TEST(Traits, actuallyRelocatable) {
164   // Ensure that we test stack and heap allocation for strings with in-situ
165   // capacity
166   testIsRelocatable<std::string>("1");
167   testIsRelocatable<std::string>(sizeof(std::string) + 1, 'x');
168
169   testIsRelocatable<std::vector<char>>(5, 'g');
170 }
171
172 struct membership_no {};
173 struct membership_yes { using x = void; };
174 FOLLY_CREATE_HAS_MEMBER_TYPE_TRAITS(has_member_type_x, x);
175
176 TEST(Traits, has_member_type) {
177   EXPECT_FALSE(bool(has_member_type_x<membership_no>::value));
178   EXPECT_TRUE(bool(has_member_type_x<membership_yes>::value));
179 }