Drop the boost dependency from Traits.h and FBVector.h
[folly.git] / folly / Traits.h
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 // @author: Andrei Alexandrescu
18
19 #pragma once
20
21 #include <memory>
22 #include <limits>
23 #include <type_traits>
24 #include <functional>
25
26 #include <folly/Portability.h>
27
28 // libc++ doesn't provide this header, nor does msvc
29 #ifdef FOLLY_HAVE_BITS_CXXCONFIG_H
30 // This file appears in two locations: inside fbcode and in the
31 // libstdc++ source code (when embedding fbstring as std::string).
32 // To aid in this schizophrenic use, two macros are defined in
33 // c++config.h:
34 //   _LIBSTDCXX_FBSTRING - Set inside libstdc++.  This is useful to
35 //      gate use inside fbcode v. libstdc++
36 #include <bits/c++config.h>
37 #endif
38
39 #define FOLLY_CREATE_HAS_MEMBER_TYPE_TRAITS(classname, type_name)              \
40   template <typename TTheClass_>                                               \
41   struct classname##__folly_traits_impl__ {                                    \
42     template <typename UTheClass_>                                             \
43     static std::true_type test(typename UTheClass_::type_name*);               \
44     template <typename>                                                        \
45     static std::false_type test(...);                                          \
46   };                                                                           \
47   template <typename TTheClass_>                                               \
48   using classname = decltype(                                                  \
49       classname##__folly_traits_impl__<TTheClass_>::template test<TTheClass_>( \
50           nullptr))
51
52 #define FOLLY_CREATE_HAS_MEMBER_FN_TRAITS_IMPL(classname, func_name, cv_qual) \
53   template <typename TTheClass_, typename RTheReturn_, typename... TTheArgs_> \
54   struct classname##__folly_traits_impl__<                                    \
55       TTheClass_,                                                             \
56       RTheReturn_(TTheArgs_...) cv_qual> {                                    \
57     template <                                                                \
58         typename UTheClass_,                                                  \
59         RTheReturn_ (UTheClass_::*)(TTheArgs_...) cv_qual>                    \
60     struct sfinae {};                                                         \
61     template <typename UTheClass_>                                            \
62     static std::true_type test(sfinae<UTheClass_, &UTheClass_::func_name>*);  \
63     template <typename>                                                       \
64     static std::false_type test(...);                                         \
65   }
66
67 /*
68  * The FOLLY_CREATE_HAS_MEMBER_FN_TRAITS is used to create traits
69  * classes that check for the existence of a member function with
70  * a given name and signature. It currently does not support
71  * checking for inherited members.
72  *
73  * Such classes receive two template parameters: the class to be checked
74  * and the signature of the member function. A static boolean field
75  * named `value` (which is also constexpr) tells whether such member
76  * function exists.
77  *
78  * Each traits class created is bound only to the member name, not to
79  * its signature nor to the type of the class containing it.
80  *
81  * Say you need to know if a given class has a member function named
82  * `test` with the following signature:
83  *
84  *    int test() const;
85  *
86  * You'd need this macro to create a traits class to check for a member
87  * named `test`, and then use this traits class to check for the signature:
88  *
89  * namespace {
90  *
91  * FOLLY_CREATE_HAS_MEMBER_FN_TRAITS(has_test_traits, test);
92  *
93  * } // unnamed-namespace
94  *
95  * void some_func() {
96  *   cout << "Does class Foo have a member int test() const? "
97  *     << boolalpha << has_test_traits<Foo, int() const>::value;
98  * }
99  *
100  * You can use the same traits class to test for a completely different
101  * signature, on a completely different class, as long as the member name
102  * is the same:
103  *
104  * void some_func() {
105  *   cout << "Does class Foo have a member int test()? "
106  *     << boolalpha << has_test_traits<Foo, int()>::value;
107  *   cout << "Does class Foo have a member int test() const? "
108  *     << boolalpha << has_test_traits<Foo, int() const>::value;
109  *   cout << "Does class Bar have a member double test(const string&, long)? "
110  *     << boolalpha << has_test_traits<Bar, double(const string&, long)>::value;
111  * }
112  *
113  * @author: Marcelo Juchem <marcelo@fb.com>
114  */
115 #define FOLLY_CREATE_HAS_MEMBER_FN_TRAITS(classname, func_name)               \
116   template <typename, typename>                                               \
117   struct classname##__folly_traits_impl__;                                    \
118   FOLLY_CREATE_HAS_MEMBER_FN_TRAITS_IMPL(classname, func_name, );             \
119   FOLLY_CREATE_HAS_MEMBER_FN_TRAITS_IMPL(classname, func_name, const);        \
120   FOLLY_CREATE_HAS_MEMBER_FN_TRAITS_IMPL(                                     \
121       classname, func_name, /* nolint */ volatile);                           \
122   FOLLY_CREATE_HAS_MEMBER_FN_TRAITS_IMPL(                                     \
123       classname, func_name, /* nolint */ volatile const);                     \
124   template <typename TTheClass_, typename TTheSignature_>                     \
125   using classname =                                                           \
126       decltype(classname##__folly_traits_impl__<TTheClass_, TTheSignature_>:: \
127                    template test<TTheClass_>(nullptr))
128
129 namespace folly {
130
131 /**
132  * IsRelocatable<T>::value describes the ability of moving around
133  * memory a value of type T by using memcpy (as opposed to the
134  * conservative approach of calling the copy constructor and then
135  * destroying the old temporary. Essentially for a relocatable type,
136  * the following two sequences of code should be semantically
137  * equivalent:
138  *
139  * void move1(T * from, T * to) {
140  *   new(to) T(from);
141  *   (*from).~T();
142  * }
143  *
144  * void move2(T * from, T * to) {
145  *   memcpy(to, from, sizeof(T));
146  * }
147  *
148  * Most C++ types are relocatable; the ones that aren't would include
149  * internal pointers or (very rarely) would need to update remote
150  * pointers to pointers tracking them. All C++ primitive types and
151  * type constructors are relocatable.
152  *
153  * This property can be used in a variety of optimizations. Currently
154  * fbvector uses this property intensively.
155  *
156  * The default conservatively assumes the type is not
157  * relocatable. Several specializations are defined for known
158  * types. You may want to add your own specializations. Do so in
159  * namespace folly and make sure you keep the specialization of
160  * IsRelocatable<SomeStruct> in the same header as SomeStruct.
161  *
162  * You may also declare a type to be relocatable by including
163  *    `typedef std::true_type IsRelocatable;`
164  * in the class header.
165  *
166  * It may be unset in a base class by overriding the typedef to false_type.
167  */
168 /*
169  * IsTriviallyCopyable describes the value semantics property. C++11 contains
170  * the type trait is_trivially_copyable; however, it is not yet implemented
171  * in gcc (as of 4.7.1), and the user may wish to specify otherwise.
172  */
173 /*
174  * IsZeroInitializable describes the property that default construction is the
175  * same as memset(dst, 0, sizeof(T)).
176  */
177
178 namespace traits_detail {
179
180 #define FOLLY_HAS_TRUE_XXX(name)                                             \
181   FOLLY_CREATE_HAS_MEMBER_TYPE_TRAITS(has_##name, name);                     \
182   template <class T>                                                         \
183   struct name##_is_true : std::is_same<typename T::name, std::true_type> {}; \
184   template <class T>                                                         \
185   struct has_true_##name : std::conditional<                                 \
186                                has_##name<T>::value,                         \
187                                name##_is_true<T>,                            \
188                                std::false_type>::type {};
189
190 FOLLY_HAS_TRUE_XXX(IsRelocatable)
191 FOLLY_HAS_TRUE_XXX(IsZeroInitializable)
192 FOLLY_HAS_TRUE_XXX(IsTriviallyCopyable)
193
194 #undef FOLLY_HAS_TRUE_XXX
195
196 // Older versions of libstdc++ do not provide std::is_trivially_copyable
197 #if defined(__clang__) && !defined(_LIBCPP_VERSION)
198 template <class T>
199 struct is_trivially_copyable
200     : std::integral_constant<bool, __is_trivially_copyable(T)> {};
201 #elif defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 5
202 template <class T>
203 struct is_trivially_copyable : std::is_trivial<T> {};
204 #else
205 template <class T>
206 using is_trivially_copyable = std::is_trivially_copyable<T>;
207 #endif
208 }
209
210 struct Ignore {
211   template <class T>
212   /* implicit */ Ignore(const T&) {}
213   template <class T>
214   const Ignore& operator=(T const&) const { return *this; }
215 };
216
217 template <class...>
218 using Ignored = Ignore;
219
220 namespace traits_detail_IsEqualityComparable {
221 Ignore operator==(Ignore, Ignore);
222
223 template <class T, class U = T>
224 struct IsEqualityComparable
225     : std::is_convertible<
226           decltype(std::declval<T>() == std::declval<U>()),
227           bool
228       > {};
229 }
230
231 /* using override */ using traits_detail_IsEqualityComparable::
232     IsEqualityComparable;
233
234 namespace traits_detail_IsLessThanComparable {
235 Ignore operator<(Ignore, Ignore);
236
237 template <class T, class U = T>
238 struct IsLessThanComparable
239     : std::is_convertible<
240           decltype(std::declval<T>() < std::declval<U>()),
241           bool
242       > {};
243 }
244
245 /* using override */ using traits_detail_IsLessThanComparable::
246     IsLessThanComparable;
247
248 namespace traits_detail_IsNothrowSwappable {
249 #if defined(_MSC_VER) || defined(__cpp_lib_is_swappable)
250 // MSVC already implements the C++17 P0185R1 proposal which
251 // adds std::is_nothrow_swappable, so use it instead.
252 template <typename T>
253 using IsNothrowSwappable = std::is_nothrow_swappable<T>;
254 #else
255 /* using override */ using std::swap;
256
257 template <class T>
258 struct IsNothrowSwappable
259     : std::integral_constant<bool,
260         std::is_nothrow_move_constructible<T>::value &&
261         noexcept(swap(std::declval<T&>(), std::declval<T&>()))
262       > {};
263 #endif
264 }
265
266 /* using override */ using traits_detail_IsNothrowSwappable::IsNothrowSwappable;
267
268 template <class T> struct IsTriviallyCopyable
269   : std::conditional<
270       traits_detail::has_IsTriviallyCopyable<T>::value,
271       traits_detail::has_true_IsTriviallyCopyable<T>,
272       traits_detail::is_trivially_copyable<T>
273     >::type {};
274
275 template <class T> struct IsRelocatable
276   : std::conditional<
277       traits_detail::has_IsRelocatable<T>::value,
278       traits_detail::has_true_IsRelocatable<T>,
279       // TODO add this line (and some tests for it) when we upgrade to gcc 4.7
280       //std::is_trivially_move_constructible<T>::value ||
281       IsTriviallyCopyable<T>
282     >::type {};
283
284 template <class T> struct IsZeroInitializable
285   : std::conditional<
286       traits_detail::has_IsZeroInitializable<T>::value,
287       traits_detail::has_true_IsZeroInitializable<T>,
288       std::integral_constant<bool, !std::is_class<T>::value>
289     >::type {};
290
291 template <typename...>
292 struct Conjunction : std::true_type {};
293 template <typename T>
294 struct Conjunction<T> : T {};
295 template <typename T, typename... TList>
296 struct Conjunction<T, TList...>
297     : std::conditional<T::value, Conjunction<TList...>, T>::type {};
298
299 template <typename...>
300 struct Disjunction : std::false_type {};
301 template <typename T>
302 struct Disjunction<T> : T {};
303 template <typename T, typename... TList>
304 struct Disjunction<T, TList...>
305     : std::conditional<T::value, T, Disjunction<TList...>>::type {};
306
307 template <typename T>
308 struct Negation : std::integral_constant<bool, !T::value> {};
309
310 template <bool... Bs>
311 struct Bools {
312   using valid_type = bool;
313   static constexpr std::size_t size() {
314     return sizeof...(Bs);
315   }
316 };
317
318 // Lighter-weight than Conjunction, but evaluates all sub-conditions eagerly.
319 template <class... Ts>
320 using StrictConjunction =
321     std::is_same<Bools<Ts::value..., true>, Bools<true, Ts::value...>>;
322
323 } // namespace folly
324
325 /**
326  * Use this macro ONLY inside namespace folly. When using it with a
327  * regular type, use it like this:
328  *
329  * // Make sure you're at namespace ::folly scope
330  * template<> FOLLY_ASSUME_RELOCATABLE(MyType)
331  *
332  * When using it with a template type, use it like this:
333  *
334  * // Make sure you're at namespace ::folly scope
335  * template<class T1, class T2>
336  * FOLLY_ASSUME_RELOCATABLE(MyType<T1, T2>)
337  */
338 #define FOLLY_ASSUME_RELOCATABLE(...) \
339   struct IsRelocatable<  __VA_ARGS__ > : std::true_type {};
340
341 /**
342  * The FOLLY_ASSUME_FBVECTOR_COMPATIBLE* macros below encode the
343  * assumption that the type is relocatable per IsRelocatable
344  * above. Many types can be assumed to satisfy this condition, but
345  * it is the responsibility of the user to state that assumption.
346  * User-defined classes will not be optimized for use with
347  * fbvector (see FBVector.h) unless they state that assumption.
348  *
349  * Use FOLLY_ASSUME_FBVECTOR_COMPATIBLE with regular types like this:
350  *
351  * FOLLY_ASSUME_FBVECTOR_COMPATIBLE(MyType)
352  *
353  * The versions FOLLY_ASSUME_FBVECTOR_COMPATIBLE_1, _2, _3, and _4
354  * allow using the macro for describing templatized classes with 1, 2,
355  * 3, and 4 template parameters respectively. For template classes
356  * just use the macro with the appropriate number and pass the name of
357  * the template to it. Example:
358  *
359  * template <class T1, class T2> class MyType { ... };
360  * ...
361  * // Make sure you're at global scope
362  * FOLLY_ASSUME_FBVECTOR_COMPATIBLE_2(MyType)
363  */
364
365 // Use this macro ONLY at global level (no namespace)
366 #define FOLLY_ASSUME_FBVECTOR_COMPATIBLE(...) \
367   namespace folly {                           \
368   template <>                                 \
369   FOLLY_ASSUME_RELOCATABLE(__VA_ARGS__)       \
370   }
371 // Use this macro ONLY at global level (no namespace)
372 #define FOLLY_ASSUME_FBVECTOR_COMPATIBLE_1(...) \
373   namespace folly {                             \
374   template <class T1>                           \
375   FOLLY_ASSUME_RELOCATABLE(__VA_ARGS__<T1>)     \
376   }
377 // Use this macro ONLY at global level (no namespace)
378 #define FOLLY_ASSUME_FBVECTOR_COMPATIBLE_2(...) \
379   namespace folly {                             \
380   template <class T1, class T2>                 \
381   FOLLY_ASSUME_RELOCATABLE(__VA_ARGS__<T1, T2>) \
382   }
383 // Use this macro ONLY at global level (no namespace)
384 #define FOLLY_ASSUME_FBVECTOR_COMPATIBLE_3(...)     \
385   namespace folly {                                 \
386   template <class T1, class T2, class T3>           \
387   FOLLY_ASSUME_RELOCATABLE(__VA_ARGS__<T1, T2, T3>) \
388   }
389 // Use this macro ONLY at global level (no namespace)
390 #define FOLLY_ASSUME_FBVECTOR_COMPATIBLE_4(...)         \
391   namespace folly {                                     \
392   template <class T1, class T2, class T3, class T4>     \
393   FOLLY_ASSUME_RELOCATABLE(__VA_ARGS__<T1, T2, T3, T4>) \
394   }
395
396 /**
397  * Instantiate FOLLY_ASSUME_FBVECTOR_COMPATIBLE for a few types. It is
398  * safe to assume that pair is compatible if both of its components
399  * are. Furthermore, all STL containers can be assumed to comply,
400  * although that is not guaranteed by the standard.
401  */
402
403 FOLLY_NAMESPACE_STD_BEGIN
404
405 template <class T, class U>
406   struct pair;
407 #ifndef _GLIBCXX_USE_FB
408 FOLLY_GLIBCXX_NAMESPACE_CXX11_BEGIN
409 template <class T, class R, class A>
410   class basic_string;
411 FOLLY_GLIBCXX_NAMESPACE_CXX11_END
412 #else
413 template <class T, class R, class A, class S>
414   class basic_string;
415 #endif
416 template <class T, class A>
417   class vector;
418 template <class T, class A>
419   class deque;
420 FOLLY_GLIBCXX_NAMESPACE_CXX11_BEGIN
421 template <class T, class A>
422   class list;
423 FOLLY_GLIBCXX_NAMESPACE_CXX11_END
424 template <class T, class C, class A>
425   class set;
426 template <class K, class V, class C, class A>
427   class map;
428 template <class T>
429   class shared_ptr;
430
431 FOLLY_NAMESPACE_STD_END
432
433 namespace folly {
434
435 // STL commonly-used types
436 template <class T, class U>
437 struct IsRelocatable< std::pair<T, U> >
438     : std::integral_constant<bool,
439         IsRelocatable<T>::value &&
440         IsRelocatable<U>::value> {};
441
442 // Is T one of T1, T2, ..., Tn?
443 template <class T, class... Ts>
444 struct IsOneOf {
445   enum { value = false };
446 };
447
448 template <class T, class T1, class... Ts>
449 struct IsOneOf<T, T1, Ts...> {
450   enum { value = std::is_same<T, T1>::value || IsOneOf<T, Ts...>::value };
451 };
452
453 /*
454  * Complementary type traits for integral comparisons.
455  *
456  * For instance, `if(x < 0)` yields an error in clang for unsigned types
457  *  when -Werror is used due to -Wtautological-compare
458  *
459  *
460  * @author: Marcelo Juchem <marcelo@fb.com>
461  */
462
463 namespace detail {
464
465 template <typename T, bool>
466 struct is_negative_impl {
467   constexpr static bool check(T x) { return x < 0; }
468 };
469
470 template <typename T>
471 struct is_negative_impl<T, false> {
472   constexpr static bool check(T) { return false; }
473 };
474
475 // folly::to integral specializations can end up generating code
476 // inside what are really static ifs (not executed because of the templated
477 // types) that violate -Wsign-compare and/or -Wbool-compare so suppress them
478 // in order to not prevent all calling code from using it.
479 FOLLY_PUSH_WARNING
480 FOLLY_GCC_DISABLE_WARNING(sign-compare)
481 #if __GNUC_PREREQ(5, 0)
482 FOLLY_GCC_DISABLE_WARNING(bool-compare)
483 #endif
484 FOLLY_MSVC_DISABLE_WARNING(4388) // sign-compare
485 FOLLY_MSVC_DISABLE_WARNING(4804) // bool-compare
486
487 template <typename RHS, RHS rhs, typename LHS>
488 bool less_than_impl(LHS const lhs) {
489   return
490     rhs > std::numeric_limits<LHS>::max() ? true :
491     rhs <= std::numeric_limits<LHS>::min() ? false :
492     lhs < rhs;
493 }
494
495 template <typename RHS, RHS rhs, typename LHS>
496 bool greater_than_impl(LHS const lhs) {
497   return
498     rhs > std::numeric_limits<LHS>::max() ? false :
499     rhs < std::numeric_limits<LHS>::min() ? true :
500     lhs > rhs;
501 }
502
503 FOLLY_POP_WARNING
504
505 } // namespace detail {
506
507 // same as `x < 0`
508 template <typename T>
509 constexpr bool is_negative(T x) {
510   return folly::detail::is_negative_impl<T, std::is_signed<T>::value>::check(x);
511 }
512
513 // same as `x <= 0`
514 template <typename T>
515 constexpr bool is_non_positive(T x) { return !x || folly::is_negative(x); }
516
517 // same as `x > 0`
518 template <typename T>
519 constexpr bool is_positive(T x) { return !is_non_positive(x); }
520
521 // same as `x >= 0`
522 template <typename T>
523 constexpr bool is_non_negative(T x) {
524   return !x || is_positive(x);
525 }
526
527 template <typename RHS, RHS rhs, typename LHS>
528 bool less_than(LHS const lhs) {
529   return detail::less_than_impl<
530     RHS, rhs, typename std::remove_reference<LHS>::type
531   >(lhs);
532 }
533
534 template <typename RHS, RHS rhs, typename LHS>
535 bool greater_than(LHS const lhs) {
536   return detail::greater_than_impl<
537     RHS, rhs, typename std::remove_reference<LHS>::type
538   >(lhs);
539 }
540
541 namespace traits_detail {
542 struct InPlaceTag {};
543 template <class>
544 struct InPlaceTypeTag {};
545 template <std::size_t>
546 struct InPlaceIndexTag {};
547 }
548
549 /**
550  * Like std::piecewise_construct, a tag type & instance used for in-place
551  * construction of non-movable contained types, e.g. by Synchronized.
552  * Follows the naming and design of std::in_place suggested in
553  * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0032r2.pdf
554  */
555 using in_place_t = traits_detail::InPlaceTag (&)(traits_detail::InPlaceTag);
556
557 template <class T>
558 using in_place_type_t =
559     traits_detail::InPlaceTypeTag<T> (&)(traits_detail::InPlaceTypeTag<T>);
560
561 template <std::size_t I>
562 using in_place_index_t =
563     traits_detail::InPlaceIndexTag<I> (&)(traits_detail::InPlaceIndexTag<I>);
564
565 inline traits_detail::InPlaceTag in_place(traits_detail::InPlaceTag = {}) {
566   return {};
567 }
568
569 template <class T>
570 inline traits_detail::InPlaceTypeTag<T> in_place(
571     traits_detail::InPlaceTypeTag<T> = {}) {
572   return {};
573 }
574
575 template <std::size_t I>
576 inline traits_detail::InPlaceIndexTag<I> in_place(
577     traits_detail::InPlaceIndexTag<I> = {}) {
578   return {};
579 }
580
581 // For backwards compatibility:
582 using construct_in_place_t = in_place_t;
583
584 inline traits_detail::InPlaceTag construct_in_place(
585     traits_detail::InPlaceTag = {}) {
586   return {};
587 }
588
589 /**
590  * Initializer lists are a powerful compile time syntax introduced in C++11
591  * but due to their often conflicting syntax they are not used by APIs for
592  * construction.
593  *
594  * Further standard conforming compilers *strongly* favor an
595  * std::initalizer_list overload for construction if one exists.  The
596  * following is a simple tag used to disambiguate construction with
597  * initializer lists and regular uniform initialization.
598  *
599  * For example consider the following case
600  *
601  *  class Something {
602  *  public:
603  *    explicit Something(int);
604  *    Something(std::intiializer_list<int>);
605  *
606  *    operator int();
607  *  };
608  *
609  *  ...
610  *  Something something{1}; // SURPRISE!!
611  *
612  * The last call to instantiate the Something object will go to the
613  * initializer_list overload.  Which may be surprising to users.
614  *
615  * If however this tag was used to disambiguate such construction it would be
616  * easy for users to see which construction overload their code was referring
617  * to.  For example
618  *
619  *  class Something {
620  *  public:
621  *    explicit Something(int);
622  *    Something(folly::initlist_construct_t, std::initializer_list<int>);
623  *
624  *    operator int();
625  *  };
626  *
627  *  ...
628  *  Something something_one{1}; // not the initializer_list overload
629  *  Something something_two{folly::initlist_construct, {1}}; // correct
630  */
631 struct initlist_construct_t {};
632 constexpr initlist_construct_t initlist_construct{};
633
634 } // namespace folly
635
636 // Assume nothing when compiling with MSVC.
637 #ifndef _MSC_VER
638 // gcc-5.0 changed string's implementation in libgcc to be non-relocatable
639 #if __GNUC__ < 5
640 FOLLY_ASSUME_FBVECTOR_COMPATIBLE_3(std::basic_string)
641 #endif
642 FOLLY_ASSUME_FBVECTOR_COMPATIBLE_2(std::vector)
643 FOLLY_ASSUME_FBVECTOR_COMPATIBLE_2(std::list)
644 FOLLY_ASSUME_FBVECTOR_COMPATIBLE_2(std::deque)
645 FOLLY_ASSUME_FBVECTOR_COMPATIBLE_2(std::unique_ptr)
646 FOLLY_ASSUME_FBVECTOR_COMPATIBLE_1(std::shared_ptr)
647 FOLLY_ASSUME_FBVECTOR_COMPATIBLE_1(std::function)
648 #endif
649
650 /* Some combinations of compilers and C++ libraries make __int128 and
651  * unsigned __int128 available but do not correctly define their standard type
652  * traits.
653  *
654  * If FOLLY_SUPPLY_MISSING_INT128_TRAITS is defined, we define these traits
655  * here.
656  *
657  * @author: Phil Willoughby <philwill@fb.com>
658  */
659 #if FOLLY_SUPPLY_MISSING_INT128_TRAITS
660 FOLLY_NAMESPACE_STD_BEGIN
661 template <>
662 struct is_arithmetic<__int128> : ::std::true_type {};
663 template <>
664 struct is_arithmetic<unsigned __int128> : ::std::true_type {};
665 template <>
666 struct is_integral<__int128> : ::std::true_type {};
667 template <>
668 struct is_integral<unsigned __int128> : ::std::true_type {};
669 template <>
670 struct make_unsigned<__int128> {
671   typedef unsigned __int128 type;
672 };
673 template <>
674 struct make_signed<__int128> {
675   typedef __int128 type;
676 };
677 template <>
678 struct make_unsigned<unsigned __int128> {
679   typedef unsigned __int128 type;
680 };
681 template <>
682 struct make_signed<unsigned __int128> {
683   typedef __int128 type;
684 };
685 template <>
686 struct is_signed<__int128> : ::std::true_type {};
687 template <>
688 struct is_unsigned<unsigned __int128> : ::std::true_type {};
689 FOLLY_NAMESPACE_STD_END
690 #endif // FOLLY_SUPPLY_MISSING_INT128_TRAITS