2 * Copyright 2013 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 // @author: Andrei Alexandrescu
19 #ifndef FOLLY_BASE_TRAITS_H_
20 #define FOLLY_BASE_TRAITS_H_
24 #include <type_traits>
26 #include "folly/Portability.h"
28 #include <bits/c++config.h>
30 #include <boost/type_traits.hpp>
31 #include <boost/mpl/and.hpp>
32 #include <boost/mpl/has_xxx.hpp>
33 #include <boost/mpl/not.hpp>
38 * IsRelocatable<T>::value describes the ability of moving around
39 * memory a value of type T by using memcpy (as opposed to the
40 * conservative approach of calling the copy constructor and then
41 * destroying the old temporary. Essentially for a relocatable type,
42 * the following two sequences of code should be semantically
45 * void move1(T * from, T * to) {
50 * void move2(T * from, T * to) {
51 * memcpy(to, from, sizeof(T));
54 * Most C++ types are relocatable; the ones that aren't would include
55 * internal pointers or (very rarely) would need to update remote
56 * pointers to pointers tracking them. All C++ primitive types and
57 * type constructors are relocatable.
59 * This property can be used in a variety of optimizations. Currently
60 * fbvector uses this property intensively.
62 * The default conservatively assumes the type is not
63 * relocatable. Several specializations are defined for known
64 * types. You may want to add your own specializations. Do so in
65 * namespace folly and make sure you keep the specialization of
66 * IsRelocatable<SomeStruct> in the same header as SomeStruct.
68 * You may also declare a type to be relocatable by including
69 * `typedef std::true_type IsRelocatable;`
70 * in the class header.
72 * It may be unset in a base class by overriding the typedef to false_type.
75 * IsTriviallyCopyable describes the value semantics property. C++11 contains
76 * the type trait is_trivially_copyable; however, it is not yet implemented
77 * in gcc (as of 4.7.1), and the user may wish to specify otherwise.
80 * IsZeroInitializable describes the property that default construction is the
81 * same as memset(dst, 0, sizeof(T)).
84 namespace traits_detail {
86 #define FOLLY_HAS_TRUE_XXX(name) \
87 BOOST_MPL_HAS_XXX_TRAIT_DEF(name); \
88 template <class T> struct name ## _is_true \
89 : std::is_same<typename T::name, std::true_type> {}; \
90 template <class T> struct has_true_ ## name \
92 has_ ## name <T>::value, \
93 name ## _is_true<T>, \
97 FOLLY_HAS_TRUE_XXX(IsRelocatable)
98 FOLLY_HAS_TRUE_XXX(IsZeroInitializable)
99 FOLLY_HAS_TRUE_XXX(IsTriviallyCopyable)
101 #undef FOLLY_HAS_TRUE_XXX
104 template <class T> struct IsTriviallyCopyable
105 : std::integral_constant<bool,
106 !std::is_class<T>::value ||
107 // TODO: add alternate clause is_trivially_copyable, when available
108 traits_detail::has_true_IsTriviallyCopyable<T>::value
111 template <class T> struct IsRelocatable
112 : std::integral_constant<bool,
113 !std::is_class<T>::value ||
114 // TODO add this line (and some tests for it) when we upgrade to gcc 4.7
115 //std::is_trivially_move_constructible<T>::value ||
116 IsTriviallyCopyable<T>::value ||
117 traits_detail::has_true_IsRelocatable<T>::value
120 template <class T> struct IsZeroInitializable
121 : std::integral_constant<bool,
122 !std::is_class<T>::value ||
123 traits_detail::has_true_IsZeroInitializable<T>::value
129 * Use this macro ONLY inside namespace folly. When using it with a
130 * regular type, use it like this:
132 * // Make sure you're at namespace ::folly scope
133 * template<> FOLLY_ASSUME_RELOCATABLE(MyType)
135 * When using it with a template type, use it like this:
137 * // Make sure you're at namespace ::folly scope
138 * template<class T1, class T2>
139 * FOLLY_ASSUME_RELOCATABLE(MyType<T1, T2>)
141 #define FOLLY_ASSUME_RELOCATABLE(...) \
142 struct IsRelocatable< __VA_ARGS__ > : std::true_type {};
145 * Use this macro ONLY inside namespace boost. When using it with a
146 * regular type, use it like this:
148 * // Make sure you're at namespace ::boost scope
149 * template<> FOLLY_ASSUME_HAS_NOTHROW_CONSTRUCTOR(MyType)
151 * When using it with a template type, use it like this:
153 * // Make sure you're at namespace ::boost scope
154 * template<class T1, class T2>
155 * FOLLY_ASSUME_HAS_NOTHROW_CONSTRUCTOR(MyType<T1, T2>)
157 #define FOLLY_ASSUME_HAS_NOTHROW_CONSTRUCTOR(...) \
158 struct has_nothrow_constructor< __VA_ARGS__ > : ::boost::true_type {};
161 * The FOLLY_ASSUME_FBVECTOR_COMPATIBLE* macros below encode two
162 * assumptions: first, that the type is relocatable per IsRelocatable
163 * above, and that it has a nothrow constructor. Most types can be
164 * assumed to satisfy both conditions, but it is the responsibility of
165 * the user to state that assumption. User-defined classes will not
166 * work with fbvector (see FBVector.h) unless they state this
167 * combination of properties.
169 * Use FOLLY_ASSUME_FBVECTOR_COMPATIBLE with regular types like this:
171 * FOLLY_ASSUME_FBVECTOR_COMPATIBLE(MyType)
173 * The versions FOLLY_ASSUME_FBVECTOR_COMPATIBLE_1, _2, _3, and _4
174 * allow using the macro for describing templatized classes with 1, 2,
175 * 3, and 4 template parameters respectively. For template classes
176 * just use the macro with the appropriate number and pass the name of
177 * the template to it. Example:
179 * template <class T1, class T2> class MyType { ... };
181 * // Make sure you're at global scope
182 * FOLLY_ASSUME_FBVECTOR_COMPATIBLE_2(MyType)
185 // Use this macro ONLY at global level (no namespace)
186 #define FOLLY_ASSUME_FBVECTOR_COMPATIBLE(...) \
187 namespace folly { template<> FOLLY_ASSUME_RELOCATABLE(__VA_ARGS__) } \
189 template<> FOLLY_ASSUME_HAS_NOTHROW_CONSTRUCTOR(__VA_ARGS__) }
190 // Use this macro ONLY at global level (no namespace)
191 #define FOLLY_ASSUME_FBVECTOR_COMPATIBLE_1(...) \
193 template <class T1> FOLLY_ASSUME_RELOCATABLE(__VA_ARGS__<T1>) } \
195 template <class T1> FOLLY_ASSUME_HAS_NOTHROW_CONSTRUCTOR(__VA_ARGS__<T1>) }
196 // Use this macro ONLY at global level (no namespace)
197 #define FOLLY_ASSUME_FBVECTOR_COMPATIBLE_2(...) \
199 template <class T1, class T2> \
200 FOLLY_ASSUME_RELOCATABLE(__VA_ARGS__<T1, T2>) } \
202 template <class T1, class T2> \
203 FOLLY_ASSUME_HAS_NOTHROW_CONSTRUCTOR(__VA_ARGS__<T1, T2>) }
204 // Use this macro ONLY at global level (no namespace)
205 #define FOLLY_ASSUME_FBVECTOR_COMPATIBLE_3(...) \
207 template <class T1, class T2, class T3> \
208 FOLLY_ASSUME_RELOCATABLE(__VA_ARGS__<T1, T2, T3>) } \
210 template <class T1, class T2, class T3> \
211 FOLLY_ASSUME_HAS_NOTHROW_CONSTRUCTOR(__VA_ARGS__<T1, T2, T3>) }
212 // Use this macro ONLY at global level (no namespace)
213 #define FOLLY_ASSUME_FBVECTOR_COMPATIBLE_4(...) \
215 template <class T1, class T2, class T3, class T4> \
216 FOLLY_ASSUME_RELOCATABLE(__VA_ARGS__<T1, T2, T3, T4>) } \
218 template <class T1, class T2, class T3, class T4> \
219 FOLLY_ASSUME_HAS_NOTHROW_CONSTRUCTOR(__VA_ARGS__<T1, T2, T3, T4>) }
222 * Instantiate FOLLY_ASSUME_FBVECTOR_COMPATIBLE for a few types. It is
223 * safe to assume that pair is compatible if both of its components
224 * are. Furthermore, all STL containers can be assumed to comply,
225 * although that is not guaranteed by the standard.
228 FOLLY_NAMESPACE_STD_BEGIN
230 template <class T, class U>
232 #ifndef _GLIBCXX_USE_FB
233 template <class T, class R, class A>
236 template <class T, class R, class A, class S>
239 template <class T, class A>
241 template <class T, class A>
243 template <class T, class A>
245 template <class T, class C, class A>
247 template <class K, class V, class C, class A>
252 FOLLY_NAMESPACE_STD_END
256 template <class T> class shared_ptr;
258 template <class T, class U>
259 struct has_nothrow_constructor< std::pair<T, U> >
260 : ::boost::mpl::and_< has_nothrow_constructor<T>,
261 has_nothrow_constructor<U> > {};
267 // STL commonly-used types
268 template <class T, class U>
269 struct IsRelocatable< std::pair<T, U> >
270 : ::boost::mpl::and_< IsRelocatable<T>, IsRelocatable<U> > {};
272 // Is T one of T1, T2, ..., Tn?
273 template <class T, class... Ts>
275 enum { value = false };
278 template <class T, class T1, class... Ts>
279 struct IsOneOf<T, T1, Ts...> {
280 enum { value = std::is_same<T, T1>::value || IsOneOf<T, Ts...>::value };
284 * A traits class to check for incomplete types.
288 * struct FullyDeclared {}; // complete type
289 * struct ForwardDeclared; // incomplete type
291 * is_complete<int>::value // evaluates to true
292 * is_complete<FullyDeclared>::value // evaluates to true
293 * is_complete<ForwardDeclared>::value // evaluates to false
295 * struct ForwardDeclared {}; // declared, at last
297 * is_complete<ForwardDeclared>::value // now it evaluates to true
299 * @author: Marcelo Juchem <marcelo@fb.com>
301 template <typename T>
303 template <unsigned long long> struct sfinae {};
304 template <typename U>
305 constexpr static bool test(sfinae<sizeof(U)>*) { return true; }
306 template <typename> constexpr static bool test(...) { return false; }
308 constexpr static bool value = test<T>(nullptr);
312 * Complementary type traits for integral comparisons.
314 * For instance, `if(x < 0)` yields an error in clang for unsigned types
315 * when -Werror is used due to -Wtautological-compare
318 * @author: Marcelo Juchem <marcelo@fb.com>
323 template <typename T, bool>
324 struct is_negative_impl {
325 constexpr static bool check(T x) { return x < 0; }
328 template <typename T>
329 struct is_negative_impl<T, false> {
330 constexpr static bool check(T x) { return false; }
333 template <typename RHS, RHS rhs, typename LHS>
335 typename std::enable_if<
336 (rhs <= std::numeric_limits<LHS>::max()
337 && rhs > std::numeric_limits<LHS>::min()),
344 template <typename RHS, RHS rhs, typename LHS>
346 typename std::enable_if<
347 (rhs > std::numeric_limits<LHS>::max()),
354 template <typename RHS, RHS rhs, typename LHS>
356 typename std::enable_if<
357 (rhs <= std::numeric_limits<LHS>::min()),
364 template <typename RHS, RHS rhs, typename LHS>
365 bool greater_than_impl(
366 typename std::enable_if<
367 (rhs <= std::numeric_limits<LHS>::max()
368 && rhs >= std::numeric_limits<LHS>::min()),
375 template <typename RHS, RHS rhs, typename LHS>
376 bool greater_than_impl(
377 typename std::enable_if<
378 (rhs > std::numeric_limits<LHS>::max()),
385 template <typename RHS, RHS rhs, typename LHS>
386 bool greater_than_impl(
387 typename std::enable_if<
388 (rhs < std::numeric_limits<LHS>::min()),
395 } // namespace detail {
398 template <typename T>
399 constexpr bool is_negative(T x) {
400 return folly::detail::is_negative_impl<T, std::is_signed<T>::value>::check(x);
404 template <typename T>
405 constexpr bool is_non_positive(T x) { return !x || folly::is_negative(x); }
408 template <typename T>
409 constexpr bool is_positive(T x) { return !is_non_positive(x); }
412 template <typename T>
413 constexpr bool is_non_negative(T x) {
414 return !x || is_positive(x);
417 template <typename RHS, RHS rhs, typename LHS>
418 bool less_than(LHS const lhs) {
419 return detail::less_than_impl<
420 RHS, rhs, typename std::remove_reference<LHS>::type
424 template <typename RHS, RHS rhs, typename LHS>
425 bool greater_than(LHS const lhs) {
426 return detail::greater_than_impl<
427 RHS, rhs, typename std::remove_reference<LHS>::type
433 FOLLY_ASSUME_FBVECTOR_COMPATIBLE_3(std::basic_string);
434 FOLLY_ASSUME_FBVECTOR_COMPATIBLE_2(std::vector);
435 FOLLY_ASSUME_FBVECTOR_COMPATIBLE_2(std::list);
436 FOLLY_ASSUME_FBVECTOR_COMPATIBLE_2(std::deque);
437 FOLLY_ASSUME_FBVECTOR_COMPATIBLE_2(std::unique_ptr);
438 FOLLY_ASSUME_FBVECTOR_COMPATIBLE_1(std::shared_ptr);
439 FOLLY_ASSUME_FBVECTOR_COMPATIBLE_1(std::function);
442 FOLLY_ASSUME_FBVECTOR_COMPATIBLE_1(boost::shared_ptr);
444 #define FOLLY_CREATE_HAS_MEMBER_FN_TRAITS_IMPL(classname, func_name, cv_qual) \
445 template <typename TTheClass_, typename RTheReturn_, typename... TTheArgs_> \
446 class classname<TTheClass_, RTheReturn_(TTheArgs_...) cv_qual> { \
448 typename UTheClass_, RTheReturn_ (UTheClass_::*)(TTheArgs_...) cv_qual \
449 > struct sfinae {}; \
450 template <typename UTheClass_> \
451 constexpr static bool test(sfinae<UTheClass_, &UTheClass_::func_name>*) \
453 template <typename> \
454 constexpr static bool test(...) { return false; } \
456 constexpr static bool value = test<TTheClass_>(nullptr); \
460 * The FOLLY_CREATE_HAS_MEMBER_FN_TRAITS is used to create traits
461 * classes that check for the existence of a member function with
462 * a given name and signature. It currently does not support
463 * checking for inherited members.
465 * Such classes receive two template parameters: the class to be checked
466 * and the signature of the member function. A static boolean field
467 * named `value` (which is also constexpr) tells whether such member
470 * Each traits class created is bound only to the member name, not to
471 * its signature nor to the type of the class containing it.
473 * Say you need to know if a given class has a member function named
474 * `test` with the following signature:
478 * You'd need this macro to create a traits class to check for a member
479 * named `test`, and then use this traits class to check for the signature:
483 * FOLLY_CREATE_HAS_MEMBER_FN_TRAITS(has_test_traits, test);
485 * } // unnamed-namespace
488 * cout << "Does class Foo have a member int test() const? "
489 * << boolalpha << has_test_traits<Foo, int() const>::value;
492 * You can use the same traits class to test for a completely different
493 * signature, on a completely different class, as long as the member name
497 * cout << "Does class Foo have a member int test()? "
498 * << boolalpha << has_test_traits<Foo, int()>::value;
499 * cout << "Does class Foo have a member int test() const? "
500 * << boolalpha << has_test_traits<Foo, int() const>::value;
501 * cout << "Does class Bar have a member double test(const string&, long)? "
502 * << boolalpha << has_test_traits<Bar, double(const string&, long)>::value;
505 * @author: Marcelo Juchem <marcelo@fb.com>
507 #define FOLLY_CREATE_HAS_MEMBER_FN_TRAITS(classname, func_name) \
508 template <typename, typename> class classname; \
509 FOLLY_CREATE_HAS_MEMBER_FN_TRAITS_IMPL(classname, func_name, ); \
510 FOLLY_CREATE_HAS_MEMBER_FN_TRAITS_IMPL(classname, func_name, const); \
511 FOLLY_CREATE_HAS_MEMBER_FN_TRAITS_IMPL(classname, func_name, volatile); \
512 FOLLY_CREATE_HAS_MEMBER_FN_TRAITS_IMPL(classname, func_name, volatile const)
514 #endif //FOLLY_BASE_TRAITS_H_