Pull from FB rev 63ce89e2f2301e6bba44a111cc7d4218022156f6
[folly.git] / folly / Traits.h
1 /*
2  * Copyright 2012 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 // @author: Andrei Alexandrescu
18
19 #ifndef FOLLY_BASE_TRAITS_H_
20 #define FOLLY_BASE_TRAITS_H_
21
22 #include <boost/type_traits.hpp>
23 #include <boost/mpl/and.hpp>
24 #include <boost/mpl/not.hpp>
25 #include <memory>
26 #include <bits/c++config.h>
27
28 namespace folly {
29
30 /**
31  * IsRelocatable<T>::value describes the ability of moving around
32  * memory a value of type T by using memcpy (as opposed to the
33  * conservative approach of calling the copy constructor and then
34  * destroying the old temporary. Essentially for a relocatable type,
35  * the following two sequences of code should be semantically
36  * equivalent:
37  *
38  * void move1(T * from, T * to) {
39  *   new(to) T(from);
40  *   (*from).~T();
41  * }
42  *
43  * void move2(T * from, T * to) {
44  *   memcpy(from, to, sizeof(T));
45  * }
46  *
47  * Most C++ types are relocatable; the ones that aren't would include
48  * internal pointers or (very rarely) would need to update remote
49  * pointers to pointers tracking them. All C++ primitive types and
50  * type constructors are relocatable.
51  *
52  * This property can be used in a variety of optimizations. Currently
53  * fbvector uses this property intensively.
54  *
55  * The default conservatively assumes the type is not
56  * relocatable. Several specializations are defined for known
57  * types. You may want to add your own specializations. Do so in
58  * namespace folly and make sure you keep the specialization of
59  * IsRelocatable<SomeStruct> in the same header as SomeStruct.
60  */
61 template <class T> struct IsRelocatable : boost::mpl::not_<boost::is_class<T> >
62 {};
63
64 } // namespace folly
65
66 /**
67  * Use this macro ONLY inside namespace folly. When using it with a
68  * regular type, use it like this:
69  *
70  * // Make sure you're at namespace ::folly scope
71  * template<> FOLLY_ASSUME_RELOCATABLE(MyType)
72  *
73  * When using it with a template type, use it like this:
74  *
75  * // Make sure you're at namespace ::folly scope
76  * template<class T, class T2>
77  * FOLLY_ASSUME_RELOCATABLE(MyType<T1, T2>)
78  */
79 #define FOLLY_ASSUME_RELOCATABLE(...) \
80   struct IsRelocatable<  __VA_ARGS__ > : ::boost::true_type {};
81
82 /**
83  * Use this macro ONLY inside namespace boost. When using it with a
84  * regular type, use it like this:
85  *
86  * // Make sure you're at namespace ::boost scope
87  * template<> FOLLY_ASSUME_HAS_NOTHROW_CONSTRUCTOR(MyType)
88  *
89  * When using it with a template type, use it like this:
90  *
91  * // Make sure you're at namespace ::boost scope
92  * template<class T, class T2>
93  * FOLLY_ASSUME_HAS_NOTHROW_CONSTRUCTOR(MyType<T1, T2>)
94  */
95 #define FOLLY_ASSUME_HAS_NOTHROW_CONSTRUCTOR(...) \
96   struct has_nothrow_constructor<  __VA_ARGS__ > : ::boost::true_type {};
97
98 /**
99  * The FOLLY_ASSUME_FBVECTOR_COMPATIBLE* macros below encode two
100  * assumptions: first, that the type is relocatable per IsRelocatable
101  * above, and that it has a nothrow constructor. Most types can be
102  * assumed to satisfy both conditions, but it is the responsibility of
103  * the user to state that assumption. User-defined classes will not
104  * work with fbvector (see FBVector.h) unless they state this
105  * combination of properties.
106  *
107  * Use FOLLY_ASSUME_FBVECTOR_COMPATIBLE with regular types like this:
108  *
109  * FOLLY_ASSUME_FBVECTOR_COMPATIBLE(MyType)
110  *
111  * The versions FOLLY_ASSUME_FBVECTOR_COMPATIBLE_1, _2, _3, and _4
112  * allow using the macro for describing templatized classes with 1, 2,
113  * 3, and 4 template parameters respectively. For template classes
114  * just use the macro with the appropriate number and pass the name of
115  * the template to it. Example:
116  *
117  * template <class T1, class T2> class MyType { ... };
118  * ...
119  * // Make sure you're at global scope
120  * FOLLY_ASSUME_FBVECTOR_COMPATIBLE_2(MyType)
121  */
122
123 // Use this macro ONLY at global level (no namespace)
124 #define FOLLY_ASSUME_FBVECTOR_COMPATIBLE(...)                           \
125   namespace folly { template<> FOLLY_ASSUME_RELOCATABLE(__VA_ARGS__) }   \
126   namespace boost { \
127   template<> FOLLY_ASSUME_HAS_NOTHROW_CONSTRUCTOR(__VA_ARGS__) }
128 // Use this macro ONLY at global level (no namespace)
129 #define FOLLY_ASSUME_FBVECTOR_COMPATIBLE_1(...)                         \
130   namespace folly {                                                     \
131   template <class T1> FOLLY_ASSUME_RELOCATABLE(__VA_ARGS__<T1>) }       \
132     namespace boost {                                                   \
133     template <class T1> FOLLY_ASSUME_HAS_NOTHROW_CONSTRUCTOR(__VA_ARGS__<T1>) }
134 // Use this macro ONLY at global level (no namespace)
135 #define FOLLY_ASSUME_FBVECTOR_COMPATIBLE_2(...)                 \
136   namespace folly {                                             \
137   template <class T1, class T2>                                 \
138   FOLLY_ASSUME_RELOCATABLE(__VA_ARGS__<T1, T2>) }               \
139     namespace boost {                                           \
140     template <class T1, class T2>                               \
141     FOLLY_ASSUME_HAS_NOTHROW_CONSTRUCTOR(__VA_ARGS__<T1, T2>) }
142 // Use this macro ONLY at global level (no namespace)
143 #define FOLLY_ASSUME_FBVECTOR_COMPATIBLE_3(...)                         \
144   namespace folly {                                                     \
145   template <class T1, class T2, class T3>                               \
146   FOLLY_ASSUME_RELOCATABLE(__VA_ARGS__<T1, T2, T3>) }                   \
147     namespace boost {                                                   \
148     template <class T1, class T2, class T3>                             \
149     FOLLY_ASSUME_HAS_NOTHROW_CONSTRUCTOR(__VA_ARGS__<T1, T2, T3>) }
150 // Use this macro ONLY at global level (no namespace)
151 #define FOLLY_ASSUME_FBVECTOR_COMPATIBLE_4(...)                         \
152   namespace folly {                                                     \
153   template <class T1, class T2, class T3, class T4>                     \
154   FOLLY_ASSUME_RELOCATABLE(__VA_ARGS__<T1, T2, T3, T4>) }               \
155     namespace boost {                                                   \
156     template <class T1, class T2, class T3, class T4>                   \
157     FOLLY_ASSUME_HAS_NOTHROW_CONSTRUCTOR(__VA_ARGS__<T1, T2, T3, T4>) }
158
159 /**
160  * Instantiate FOLLY_ASSUME_FBVECTOR_COMPATIBLE for a few types. It is
161  * safe to assume that pair is compatible if both of its components
162  * are. Furthermore, all STL containers can be assumed to comply,
163  * although that is not guaranteed by the standard.
164  */
165
166 namespace std {
167
168 template <class T, class U>
169   class pair;
170 #ifndef _GLIBCXX_USE_FB
171 template <class T, class R, class A>
172   class basic_string;
173 #else
174 template <class T, class R, class A, class S>
175   class basic_string;
176 #endif
177 template <class T, class A>
178   class vector;
179 template <class T, class A>
180   class deque;
181 template <class T, class A>
182   class list;
183 template <class T, class C, class A>
184   class set;
185 template <class K, class V, class C, class A>
186   class map;
187 template <class T>
188   class shared_ptr;
189
190 }
191
192 namespace boost {
193
194 template <class T> class shared_ptr;
195
196 template <class T, class U>
197 struct has_nothrow_constructor< std::pair<T, U> >
198     : ::boost::mpl::and_< has_nothrow_constructor<T>,
199                           has_nothrow_constructor<U> > {};
200
201 } // namespace boost
202
203 namespace folly {
204
205 // STL commonly-used types
206 template <class T, class U>
207 struct IsRelocatable<  std::pair<T, U> >
208     : ::boost::mpl::and_< IsRelocatable<T>, IsRelocatable<U> > {};
209
210 // Is T one of T1, T2, ..., Tn?
211 template <class T, class... Ts>
212 struct IsOneOf {
213   enum { value = false };
214 };
215
216 template <class T, class T1, class... Ts>
217 struct IsOneOf<T, T1, Ts...> {
218   enum { value = std::is_same<T, T1>::value || IsOneOf<T, Ts...>::value };
219 };
220
221 } // namespace folly
222
223 FOLLY_ASSUME_FBVECTOR_COMPATIBLE_3(std::basic_string);
224 FOLLY_ASSUME_FBVECTOR_COMPATIBLE_2(std::vector);
225 FOLLY_ASSUME_FBVECTOR_COMPATIBLE_2(std::list);
226 FOLLY_ASSUME_FBVECTOR_COMPATIBLE_2(std::deque);
227 FOLLY_ASSUME_FBVECTOR_COMPATIBLE_4(std::map);
228 FOLLY_ASSUME_FBVECTOR_COMPATIBLE_3(std::set);
229 FOLLY_ASSUME_FBVECTOR_COMPATIBLE_2(std::unique_ptr);
230 FOLLY_ASSUME_FBVECTOR_COMPATIBLE_1(std::shared_ptr);
231 FOLLY_ASSUME_FBVECTOR_COMPATIBLE_1(std::function);
232
233 // Boost
234 FOLLY_ASSUME_FBVECTOR_COMPATIBLE_1(boost::shared_ptr);
235
236 #endif //FOLLY_BASE_TRAITS_H_