proxygen
Traits.h
Go to the documentation of this file.
1 /*
2  * Copyright 2011-present 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 <functional>
22 #include <limits>
23 #include <memory>
24 #include <type_traits>
25 
26 #include <folly/Portability.h>
27 
28 // libc++ doesn't provide this header, nor does msvc
29 #if __has_include(<bits/c++config.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 constexpr bool test(typename UTheClass_::type_name*) { \
44  return true; \
45  } \
46  template <typename> \
47  static constexpr bool test(...) { \
48  return false; \
49  } \
50  }; \
51  template <typename TTheClass_> \
52  using classname = typename std::conditional< \
53  classname##__folly_traits_impl__<TTheClass_>::template test<TTheClass_>( \
54  nullptr), \
55  std::true_type, \
56  std::false_type>::type
57 
58 #define FOLLY_CREATE_HAS_MEMBER_FN_TRAITS_IMPL(classname, func_name, cv_qual) \
59  template <typename TTheClass_, typename RTheReturn_, typename... TTheArgs_> \
60  struct classname##__folly_traits_impl__< \
61  TTheClass_, \
62  RTheReturn_(TTheArgs_...) cv_qual> { \
63  template < \
64  typename UTheClass_, \
65  RTheReturn_ (UTheClass_::*)(TTheArgs_...) cv_qual> \
66  struct sfinae {}; \
67  template <typename UTheClass_> \
68  static std::true_type test(sfinae<UTheClass_, &UTheClass_::func_name>*); \
69  template <typename> \
70  static std::false_type test(...); \
71  }
72 
73 /*
74  * The FOLLY_CREATE_HAS_MEMBER_FN_TRAITS is used to create traits
75  * classes that check for the existence of a member function with
76  * a given name and signature. It currently does not support
77  * checking for inherited members.
78  *
79  * Such classes receive two template parameters: the class to be checked
80  * and the signature of the member function. A static boolean field
81  * named `value` (which is also constexpr) tells whether such member
82  * function exists.
83  *
84  * Each traits class created is bound only to the member name, not to
85  * its signature nor to the type of the class containing it.
86  *
87  * Say you need to know if a given class has a member function named
88  * `test` with the following signature:
89  *
90  * int test() const;
91  *
92  * You'd need this macro to create a traits class to check for a member
93  * named `test`, and then use this traits class to check for the signature:
94  *
95  * namespace {
96  *
97  * FOLLY_CREATE_HAS_MEMBER_FN_TRAITS(has_test_traits, test);
98  *
99  * } // unnamed-namespace
100  *
101  * void some_func() {
102  * cout << "Does class Foo have a member int test() const? "
103  * << boolalpha << has_test_traits<Foo, int() const>::value;
104  * }
105  *
106  * You can use the same traits class to test for a completely different
107  * signature, on a completely different class, as long as the member name
108  * is the same:
109  *
110  * void some_func() {
111  * cout << "Does class Foo have a member int test()? "
112  * << boolalpha << has_test_traits<Foo, int()>::value;
113  * cout << "Does class Foo have a member int test() const? "
114  * << boolalpha << has_test_traits<Foo, int() const>::value;
115  * cout << "Does class Bar have a member double test(const string&, long)? "
116  * << boolalpha << has_test_traits<Bar, double(const string&, long)>::value;
117  * }
118  *
119  * @author: Marcelo Juchem <marcelo@fb.com>
120  */
121 #define FOLLY_CREATE_HAS_MEMBER_FN_TRAITS(classname, func_name) \
122  template <typename, typename> \
123  struct classname##__folly_traits_impl__; \
124  FOLLY_CREATE_HAS_MEMBER_FN_TRAITS_IMPL(classname, func_name, ); \
125  FOLLY_CREATE_HAS_MEMBER_FN_TRAITS_IMPL(classname, func_name, const); \
126  FOLLY_CREATE_HAS_MEMBER_FN_TRAITS_IMPL( \
127  classname, func_name, /* nolint */ volatile); \
128  FOLLY_CREATE_HAS_MEMBER_FN_TRAITS_IMPL( \
129  classname, func_name, /* nolint */ volatile const); \
130  template <typename TTheClass_, typename TTheSignature_> \
131  using classname = \
132  decltype(classname##__folly_traits_impl__<TTheClass_, TTheSignature_>:: \
133  template test<TTheClass_>(nullptr))
134 
135 namespace folly {
136 
137 #if __cpp_lib_bool_constant || _MSC_VER
138 
139 using std::bool_constant;
140 
141 #else
142 
143 // mimic: std::bool_constant, C++17
144 template <bool B>
145 using bool_constant = std::integral_constant<bool, B>;
146 
147 #endif
148 
149 template <std::size_t I>
150 using index_constant = std::integral_constant<std::size_t, I>;
151 
152 /***
153  * _t
154  *
155  * Instead of:
156  *
157  * using decayed = typename std::decay<T>::type;
158  *
159  * With the C++14 standard trait aliases, we could use:
160  *
161  * using decayed = std::decay_t<T>;
162  *
163  * Without them, we could use:
164  *
165  * using decayed = _t<std::decay<T>>;
166  *
167  * Also useful for any other library with template types having dependent
168  * member types named `type`, like the standard trait types.
169  */
170 template <typename T>
171 using _t = typename T::type;
172 
177 template <typename T>
178 struct remove_cvref {
179  using type =
181 };
182 template <typename T>
184 
185 namespace detail {
186 template <typename Src>
187 struct like_ {
188  template <typename Dst>
189  using apply = Dst;
190 };
191 template <typename Src>
192 struct like_<Src const> {
193  template <typename Dst>
194  using apply = Dst const;
195 };
196 template <typename Src>
197 struct like_<Src volatile> {
198  template <typename Dst>
199  using apply = Dst volatile;
200 };
201 template <typename Src>
202 struct like_<Src const volatile> {
203  template <typename Dst>
204  using apply = Dst const volatile;
205 };
206 template <typename Src>
207 struct like_<Src&> {
208  template <typename Dst>
210 };
211 template <typename Src>
212 struct like_<Src&&> {
213  template <typename Dst>
215 };
216 } // namespace detail
217 
218 // mimic: like_t, p0847r0
219 template <typename Src, typename Dst>
220 using like_t = typename detail::like_<Src>::template apply<remove_cvref_t<Dst>>;
221 
222 // mimic: like, p0847r0
223 template <typename Src, typename Dst>
224 struct like {
226 };
227 
292 namespace traits_detail {
293 template <class T, class...>
294 struct type_t_ {
295  using type = T;
296 };
297 } // namespace traits_detail
298 
299 template <class T, class... Ts>
300 using type_t = typename traits_detail::type_t_<T, Ts...>::type;
301 template <class... Ts>
302 using void_t = type_t<void, Ts...>;
303 
304 // Older versions of libstdc++ do not provide std::is_trivially_copyable
305 #if defined(__clang__) && !defined(_LIBCPP_VERSION)
306 template <class T>
307 struct is_trivially_copyable : bool_constant<__is_trivially_copyable(T)> {};
308 #elif defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 5
309 template <class T>
310 struct is_trivially_copyable : std::is_trivial<T> {};
311 #else
312 template <class T>
313 using is_trivially_copyable = std::is_trivially_copyable<T>;
314 #endif
315 
353 /*
354  * IsZeroInitializable describes the property that default construction is the
355  * same as memset(dst, 0, sizeof(T)).
356  */
357 
358 namespace traits_detail {
359 
360 #define FOLLY_HAS_TRUE_XXX(name) \
361  FOLLY_CREATE_HAS_MEMBER_TYPE_TRAITS(has_##name, name); \
362  template <class T> \
363  struct name##_is_true : std::is_same<typename T::name, std::true_type> {}; \
364  template <class T> \
365  struct has_true_##name : std::conditional< \
366  has_##name<T>::value, \
367  name##_is_true<T>, \
368  std::false_type>::type {}
369 
372 
373 #undef FOLLY_HAS_TRUE_XXX
374 
375 } // namespace traits_detail
376 
377 struct Ignore {
378  Ignore() = default;
379  template <class T>
380  constexpr /* implicit */ Ignore(const T&) {}
381  template <class T>
382  const Ignore& operator=(T const&) const {
383  return *this;
384  }
385 };
386 
387 template <class...>
388 using Ignored = Ignore;
389 
390 namespace traits_detail_IsEqualityComparable {
392 
393 template <class T, class U = T>
395  : std::is_convertible<
396  decltype(std::declval<T>() == std::declval<U>()),
397  bool> {};
398 } // namespace traits_detail_IsEqualityComparable
399 
400 /* using override */ using traits_detail_IsEqualityComparable::
402 
403 namespace traits_detail_IsLessThanComparable {
405 
406 template <class T, class U = T>
408  : std::is_convertible<
409  decltype(std::declval<T>() < std::declval<U>()),
410  bool> {};
411 } // namespace traits_detail_IsLessThanComparable
412 
413 /* using override */ using traits_detail_IsLessThanComparable::
414  IsLessThanComparable;
415 
416 namespace traits_detail_IsNothrowSwappable {
417 #if defined(__cpp_lib_is_swappable) || (_CPPLIB_VER && _HAS_CXX17)
418 // MSVC 2015+ already implements the C++17 P0185R1 proposal which
419 // adds std::is_nothrow_swappable, so use it instead if C++17 mode
420 // is enabled.
421 template <typename T>
422 using IsNothrowSwappable = std::is_nothrow_swappable<T>;
423 #elif _CPPLIB_VER
424 // MSVC 2015+ defines the base even if C++17 is disabled, and
425 // MSVC 2015 has issues with our fallback implementation due to
426 // over-eager evaluation of noexcept.
427 template <typename T>
428 using IsNothrowSwappable = std::_Is_nothrow_swappable<T>;
429 #else
430 /* using override */ using std::swap;
431 
432 template <class T>
433 struct IsNothrowSwappable
434  : bool_constant<std::is_nothrow_move_constructible<T>::value&& noexcept(
435  swap(std::declval<T&>(), std::declval<T&>()))> {};
436 #endif
437 } // namespace traits_detail_IsNothrowSwappable
438 
439 /* using override */ using traits_detail_IsNothrowSwappable::IsNothrowSwappable;
440 
441 template <class T>
442 struct IsRelocatable : std::conditional<
443  traits_detail::has_IsRelocatable<T>::value,
444  traits_detail::has_true_IsRelocatable<T>,
445  // TODO add this line (and some tests for it) when we
446  // upgrade to gcc 4.7
447  // std::is_trivially_move_constructible<T>::value ||
448  is_trivially_copyable<T>>::type {};
449 
450 template <class T>
451 struct IsZeroInitializable
452  : std::conditional<
453  traits_detail::has_IsZeroInitializable<T>::value,
454  traits_detail::has_true_IsZeroInitializable<T>,
455  bool_constant<!std::is_class<T>::value>>::type {};
456 
457 template <typename...>
458 struct Conjunction : std::true_type {};
459 template <typename T>
460 struct Conjunction<T> : T {};
461 template <typename T, typename... TList>
462 struct Conjunction<T, TList...>
463  : std::conditional<T::value, Conjunction<TList...>, T>::type {};
464 
465 template <typename...>
466 struct Disjunction : std::false_type {};
467 template <typename T>
468 struct Disjunction<T> : T {};
469 template <typename T, typename... TList>
470 struct Disjunction<T, TList...>
471  : std::conditional<T::value, T, Disjunction<TList...>>::type {};
472 
473 template <typename T>
474 struct Negation : bool_constant<!T::value> {};
475 
476 template <bool... Bs>
477 struct Bools {
478  using valid_type = bool;
479  static constexpr std::size_t size() {
480  return sizeof...(Bs);
481  }
482 };
483 
484 // Lighter-weight than Conjunction, but evaluates all sub-conditions eagerly.
485 template <class... Ts>
486 struct StrictConjunction
487  : std::is_same<Bools<Ts::value...>, Bools<(Ts::value || true)...>> {};
488 
489 template <class... Ts>
490 struct StrictDisjunction
491  : Negation<
492  std::is_same<Bools<Ts::value...>, Bools<(Ts::value && false)...>>> {};
493 
494 } // namespace folly
495 
509 #define FOLLY_ASSUME_RELOCATABLE(...) \
510  struct IsRelocatable<__VA_ARGS__> : std::true_type {}
511 
536 // Use this macro ONLY at global level (no namespace)
537 #define FOLLY_ASSUME_FBVECTOR_COMPATIBLE(...) \
538  namespace folly { \
539  template <> \
540  FOLLY_ASSUME_RELOCATABLE(__VA_ARGS__); \
541  }
542 // Use this macro ONLY at global level (no namespace)
543 #define FOLLY_ASSUME_FBVECTOR_COMPATIBLE_1(...) \
544  namespace folly { \
545  template <class T1> \
546  FOLLY_ASSUME_RELOCATABLE(__VA_ARGS__<T1>); \
547  }
548 // Use this macro ONLY at global level (no namespace)
549 #define FOLLY_ASSUME_FBVECTOR_COMPATIBLE_2(...) \
550  namespace folly { \
551  template <class T1, class T2> \
552  FOLLY_ASSUME_RELOCATABLE(__VA_ARGS__<T1, T2>); \
553  }
554 // Use this macro ONLY at global level (no namespace)
555 #define FOLLY_ASSUME_FBVECTOR_COMPATIBLE_3(...) \
556  namespace folly { \
557  template <class T1, class T2, class T3> \
558  FOLLY_ASSUME_RELOCATABLE(__VA_ARGS__<T1, T2, T3>); \
559  }
560 // Use this macro ONLY at global level (no namespace)
561 #define FOLLY_ASSUME_FBVECTOR_COMPATIBLE_4(...) \
562  namespace folly { \
563  template <class T1, class T2, class T3, class T4> \
564  FOLLY_ASSUME_RELOCATABLE(__VA_ARGS__<T1, T2, T3, T4>); \
565  }
566 
574 FOLLY_NAMESPACE_STD_BEGIN
575 
576 template <class T, class U>
577 struct pair;
578 #ifndef _GLIBCXX_USE_FB
579 FOLLY_GLIBCXX_NAMESPACE_CXX11_BEGIN
580 template <class T, class R, class A>
581 class basic_string;
582 FOLLY_GLIBCXX_NAMESPACE_CXX11_END
583 #else
584 template <class T, class R, class A, class S>
585 class basic_string;
586 #endif
587 template <class T, class A>
588 class vector;
589 template <class T, class A>
590 class deque;
591 template <class T, class C, class A>
592 class set;
593 template <class K, class V, class C, class A>
594 class map;
595 template <class T>
596 class shared_ptr;
597 
598 FOLLY_NAMESPACE_STD_END
599 
600 namespace folly {
601 
602 // STL commonly-used types
603 template <class T, class U>
604 struct IsRelocatable<std::pair<T, U>>
605  : bool_constant<IsRelocatable<T>::value && IsRelocatable<U>::value> {};
606 
607 // Is T one of T1, T2, ..., Tn?
608 template <typename T, typename... Ts>
609 using IsOneOf = StrictDisjunction<std::is_same<T, Ts>...>;
610 
611 /*
612  * Complementary type traits for integral comparisons.
613  *
614  * For instance, `if(x < 0)` yields an error in clang for unsigned types
615  * when -Werror is used due to -Wtautological-compare
616  *
617  *
618  * @author: Marcelo Juchem <marcelo@fb.com>
619  */
620 
621 namespace detail {
622 
623 template <typename T, bool>
624 struct is_negative_impl {
625  constexpr static bool check(T x) {
626  return x < 0;
627  }
628 };
629 
630 template <typename T>
631 struct is_negative_impl<T, false> {
632  constexpr static bool check(T) {
633  return false;
634  }
635 };
636 
637 // folly::to integral specializations can end up generating code
638 // inside what are really static ifs (not executed because of the templated
639 // types) that violate -Wsign-compare and/or -Wbool-compare so suppress them
640 // in order to not prevent all calling code from using it.
641 FOLLY_PUSH_WARNING
642 FOLLY_GNU_DISABLE_WARNING("-Wsign-compare")
643 #if __GNUC_PREREQ(5, 0)
644 FOLLY_GNU_DISABLE_WARNING("-Wbool-compare")
645 #endif
646 FOLLY_MSVC_DISABLE_WARNING(4388) // sign-compare
647 FOLLY_MSVC_DISABLE_WARNING(4804) // bool-compare
648 
649 template <typename RHS, RHS rhs, typename LHS>
650 bool less_than_impl(LHS const lhs) {
651  // clang-format off
652  return
653  rhs > std::numeric_limits<LHS>::max() ? true :
654  rhs <= std::numeric_limits<LHS>::min() ? false :
655  lhs < rhs;
656  // clang-format on
657 }
658 
659 template <typename RHS, RHS rhs, typename LHS>
660 bool greater_than_impl(LHS const lhs) {
661  // clang-format off
662  return
663  rhs > std::numeric_limits<LHS>::max() ? false :
664  rhs < std::numeric_limits<LHS>::min() ? true :
665  lhs > rhs;
666  // clang-format on
667 }
668 
669 FOLLY_POP_WARNING
670 
671 } // namespace detail
672 
673 // same as `x < 0`
674 template <typename T>
675 constexpr bool is_negative(T x) {
676  return folly::detail::is_negative_impl<T, std::is_signed<T>::value>::check(x);
677 }
678 
679 // same as `x <= 0`
680 template <typename T>
681 constexpr bool is_non_positive(T x) {
682  return !x || folly::is_negative(x);
683 }
684 
685 // same as `x > 0`
686 template <typename T>
687 constexpr bool is_positive(T x) {
688  return !is_non_positive(x);
689 }
690 
691 // same as `x >= 0`
692 template <typename T>
693 constexpr bool is_non_negative(T x) {
694  return !x || is_positive(x);
695 }
696 
697 template <typename RHS, RHS rhs, typename LHS>
698 bool less_than(LHS const lhs) {
699  return detail::
700  less_than_impl<RHS, rhs, typename std::remove_reference<LHS>::type>(lhs);
701 }
702 
703 template <typename RHS, RHS rhs, typename LHS>
704 bool greater_than(LHS const lhs) {
705  return detail::
706  greater_than_impl<RHS, rhs, typename std::remove_reference<LHS>::type>(
707  lhs);
708 }
709 } // namespace folly
710 
711 // Assume nothing when compiling with MSVC.
712 #ifndef _MSC_VER
713 // gcc-5.0 changed string's implementation in libstdc++ to be non-relocatable
714 #if !_GLIBCXX_USE_CXX11_ABI
715 FOLLY_ASSUME_FBVECTOR_COMPATIBLE_3(std::basic_string)
716 #endif
717 FOLLY_ASSUME_FBVECTOR_COMPATIBLE_2(std::vector)
718 FOLLY_ASSUME_FBVECTOR_COMPATIBLE_2(std::deque)
719 FOLLY_ASSUME_FBVECTOR_COMPATIBLE_2(std::unique_ptr)
720 FOLLY_ASSUME_FBVECTOR_COMPATIBLE_1(std::shared_ptr)
721 FOLLY_ASSUME_FBVECTOR_COMPATIBLE_1(std::function)
722 #endif
723 
724 /* Some combinations of compilers and C++ libraries make __int128 and
725  * unsigned __int128 available but do not correctly define their standard type
726  * traits.
727  *
728  * If FOLLY_SUPPLY_MISSING_INT128_TRAITS is defined, we define these traits
729  * here.
730  *
731  * @author: Phil Willoughby <philwill@fb.com>
732  */
733 #if FOLLY_SUPPLY_MISSING_INT128_TRAITS
734 FOLLY_NAMESPACE_STD_BEGIN
735 template <>
736 struct is_arithmetic<__int128> : ::std::true_type {};
737 template <>
738 struct is_arithmetic<unsigned __int128> : ::std::true_type {};
739 template <>
740 struct is_integral<__int128> : ::std::true_type {};
741 template <>
742 struct is_integral<unsigned __int128> : ::std::true_type {};
743 template <>
744 struct make_unsigned<__int128> {
745  typedef unsigned __int128 type;
746 };
747 template <>
748 struct make_signed<__int128> {
749  typedef __int128 type;
750 };
751 template <>
752 struct make_unsigned<unsigned __int128> {
753  typedef unsigned __int128 type;
754 };
755 template <>
756 struct make_signed<unsigned __int128> {
757  typedef __int128 type;
758 };
759 template <>
760 struct is_signed<__int128> : ::std::true_type {};
761 template <>
762 struct is_unsigned<unsigned __int128> : ::std::true_type {};
763 FOLLY_NAMESPACE_STD_END
764 #endif // FOLLY_SUPPLY_MISSING_INT128_TRAITS
typename remove_cvref< T >::type remove_cvref_t
Definition: Traits.h:183
typename like_< Src >::template apply< Dst > & apply
Definition: Traits.h:209
PskType type
std::integral_constant< std::size_t, I > index_constant
Definition: Traits.h:150
folly::std T
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
like_t< Src, Dst > type
Definition: Traits.h:225
typename traits_detail::type_t_< T, Ts... >::type type_t
Definition: Traits.h:300
std::integral_constant< bool, B > bool_constant
Definition: Traits.h:145
typename detail::like_< Src >::template apply< remove_cvref_t< Dst >> like_t
Definition: Traits.h:220
typename T::type _t
Definition: Traits.h:171
#define FOLLY_HAS_TRUE_XXX(name)
Definition: Traits.h:360
type_t< void, Ts... > void_t
Definition: Traits.h:302
std::is_trivially_copyable< T > is_trivially_copyable
Definition: Traits.h:313
typename std::remove_cv< typename std::remove_reference< T >::type >::type type
Definition: Traits.h:180
bool operator==(const Unexpected< Error > &lhs, const Unexpected< Error > &rhs)
Definition: Expected.h:758
typename like_< Src >::template apply< Dst > && apply
Definition: Traits.h:214
const
Definition: upload.py:398
const Ignore & operator=(T const &) const
Definition: Traits.h:382
std::enable_if< IsLessThanComparable< Value >::value, bool >::type operator<(const Expected< Value, Error > &lhs, const Expected< Value, Error > &rhs)
Definition: Expected.h:1321
constexpr Ignore(const T &)
Definition: Traits.h:380