1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef BASE_TEMPLATE_UTIL_H_ 6 #define BASE_TEMPLATE_UTIL_H_ 7 8 #include <stddef.h> 9 #include <iosfwd> 10 #include <type_traits> 11 #include <utility> 12 13 #include "third_party/build/build_config.h" 14 15 // This hacks around libstdc++ 4.6 missing stuff in type_traits, while we need 16 // to support it. 17 #define CR_GLIBCXX_4_7_0 20120322 18 #define CR_GLIBCXX_4_5_4 20120702 19 #define CR_GLIBCXX_4_6_4 20121127 20 #if defined(__GLIBCXX__) && \ 21 (__GLIBCXX__ < CR_GLIBCXX_4_7_0 || __GLIBCXX__ == CR_GLIBCXX_4_5_4 || \ 22 __GLIBCXX__ == CR_GLIBCXX_4_6_4) 23 #define CR_USE_FALLBACKS_FOR_OLD_GLIBCXX 24 #endif 25 26 // Some versions of libstdc++ have partial support for type_traits, but misses 27 // a smaller subset while removing some of the older non-standard stuff. Assume 28 // that all versions below 5.0 fall in this category, along with one 5.0 29 // experimental release. Test for this by consulting compiler major version, 30 // the only reliable option available, so theoretically this could fail should 31 // you attempt to mix an earlier version of libstdc++ with >= GCC5. But 32 // that's unlikely to work out, especially as GCC5 changed ABI. 33 #define CR_GLIBCXX_5_0_0 20150123 34 #if (defined(__GNUC__) && __GNUC__ < 5) || \ 35 (defined(__GLIBCXX__) && __GLIBCXX__ == CR_GLIBCXX_5_0_0) 36 #define CR_USE_FALLBACKS_FOR_OLD_EXPERIMENTAL_GLIBCXX 37 #endif 38 39 // This hacks around using gcc with libc++ which has some incompatibilies. 40 // - is_trivially_* doesn't work: https://llvm.org/bugs/show_bug.cgi?id=27538 41 // TODO(danakj): Remove this when android builders are all using a newer version 42 // of gcc, or the android ndk is updated to a newer libc++ that works with older 43 // gcc versions. 44 #if !defined(__clang__) && defined(_LIBCPP_VERSION) 45 #define CR_USE_FALLBACKS_FOR_GCC_WITH_LIBCXX 46 #endif 47 48 namespace base { 49 50 template <class T> 51 struct is_non_const_reference : std::false_type {}; 52 template <class T> 53 struct is_non_const_reference<T&> : std::true_type {}; 54 template <class T> 55 struct is_non_const_reference<const T&> : std::false_type {}; 56 57 // is_assignable 58 59 namespace internal { 60 61 template <typename First, typename Second> 62 struct SelectSecond { 63 using type = Second; 64 }; 65 66 struct Any { 67 Any(...); 68 }; 69 70 // True case: If |Lvalue| can be assigned to from |Rvalue|, then the return 71 // value is a true_type. 72 template <class Lvalue, class Rvalue> 73 typename internal::SelectSecond< 74 decltype((std::declval<Lvalue>() = std::declval<Rvalue>())), 75 std::true_type>::type 76 IsAssignableTest(Lvalue&&, Rvalue&&); 77 78 // False case: Otherwise the return value is a false_type. 79 template <class Rvalue> 80 std::false_type IsAssignableTest(internal::Any, Rvalue&&); 81 82 // Default case: Neither Lvalue nor Rvalue is void. Uses IsAssignableTest to 83 // determine the type of IsAssignableImpl. 84 template <class Lvalue, 85 class Rvalue, 86 bool = std::is_void<Lvalue>::value || std::is_void<Rvalue>::value> 87 struct IsAssignableImpl 88 : public std::common_type<decltype( 89 internal::IsAssignableTest(std::declval<Lvalue>(), 90 std::declval<Rvalue>()))>::type {}; 91 92 // Void case: Either Lvalue or Rvalue is void. Then the type of IsAssignableTest 93 // is false_type. 94 template <class Lvalue, class Rvalue> 95 struct IsAssignableImpl<Lvalue, Rvalue, true> : public std::false_type {}; 96 97 // Uses expression SFINAE to detect whether using operator<< would work. 98 template <typename T, typename = void> 99 struct SupportsOstreamOperator : std::false_type {}; 100 template <typename T> 101 struct SupportsOstreamOperator<T, 102 decltype(void(std::declval<std::ostream&>() 103 << std::declval<T>()))> 104 : std::true_type {}; 105 106 } // namespace internal 107 108 // TODO(crbug.com/554293): Remove this when all platforms have this in the std 109 // namespace. 110 template <class Lvalue, class Rvalue> 111 struct is_assignable : public internal::IsAssignableImpl<Lvalue, Rvalue> {}; 112 113 // is_copy_assignable is true if a T const& is assignable to a T&. 114 // TODO(crbug.com/554293): Remove this when all platforms have this in the std 115 // namespace. 116 template <class T> 117 struct is_copy_assignable 118 : public is_assignable<typename std::add_lvalue_reference<T>::type, 119 typename std::add_lvalue_reference< 120 typename std::add_const<T>::type>::type> {}; 121 122 // is_move_assignable is true if a T&& is assignable to a T&. 123 // TODO(crbug.com/554293): Remove this when all platforms have this in the std 124 // namespace. 125 template <class T> 126 struct is_move_assignable 127 : public is_assignable<typename std::add_lvalue_reference<T>::type, 128 const typename std::add_rvalue_reference<T>::type> { 129 }; 130 131 // underlying_type produces the integer type backing an enum type. 132 // TODO(crbug.com/554293): Remove this when all platforms have this in the std 133 // namespace. 134 #if defined(CR_USE_FALLBACKS_FOR_OLD_GLIBCXX) 135 template <typename T> 136 struct underlying_type { 137 using type = __underlying_type(T); 138 }; 139 #else 140 template <typename T> 141 using underlying_type = std::underlying_type<T>; 142 #endif 143 144 // TODO(crbug.com/554293): Remove this when all platforms have this in the std 145 // namespace. 146 #if defined(CR_USE_FALLBACKS_FOR_OLD_GLIBCXX) 147 template <class T> 148 using is_trivially_destructible = std::has_trivial_destructor<T>; 149 #else 150 template <class T> 151 using is_trivially_destructible = std::is_trivially_destructible<T>; 152 #endif 153 154 // is_trivially_copyable is especially hard to get right. 155 // - Older versions of libstdc++ will fail to have it like they do for other 156 // type traits. In this case we should provide it based on compiler 157 // intrinsics. This is covered by the CR_USE_FALLBACKS_FOR_OLD_GLIBCXX define. 158 // - An experimental release of gcc includes most of type_traits but misses 159 // is_trivially_copyable, so we still have to avoid using libstdc++ in this 160 // case, which is covered by CR_USE_FALLBACKS_FOR_OLD_EXPERIMENTAL_GLIBCXX. 161 // - When compiling libc++ from before r239653, with a gcc compiler, the 162 // std::is_trivially_copyable can fail. So we need to work around that by not 163 // using the one in libc++ in this case. This is covered by the 164 // CR_USE_FALLBACKS_FOR_GCC_WITH_LIBCXX define, and is discussed in 165 // https://llvm.org/bugs/show_bug.cgi?id=27538#c1 where they point out that 166 // in libc++'s commit r239653 this is fixed by libc++ checking for gcc 5.1. 167 // - In both of the above cases we are using the gcc compiler. When defining 168 // this ourselves on compiler intrinsics, the __is_trivially_copyable() 169 // intrinsic is not available on gcc before version 5.1 (see the discussion in 170 // https://llvm.org/bugs/show_bug.cgi?id=27538#c1 again), so we must check for 171 // that version. 172 // - When __is_trivially_copyable() is not available because we are on gcc older 173 // than 5.1, we need to fall back to something, so we use __has_trivial_copy() 174 // instead based on what was done one-off in bit_cast() previously. 175 176 // TODO(crbug.com/554293): Remove this when all platforms have this in the std 177 // namespace and it works with gcc as needed. 178 #if defined(CR_USE_FALLBACKS_FOR_OLD_GLIBCXX) || \ 179 defined(CR_USE_FALLBACKS_FOR_OLD_EXPERIMENTAL_GLIBCXX) || \ 180 defined(CR_USE_FALLBACKS_FOR_GCC_WITH_LIBCXX) 181 template <typename T> 182 struct is_trivially_copyable { 183 // TODO(danakj): Remove this when android builders are all using a newer version 184 // of gcc, or the android ndk is updated to a newer libc++ that does this for 185 // us. 186 #if _GNUC_VER >= 501 187 static constexpr bool value = __is_trivially_copyable(T); 188 #else 189 static constexpr bool value = __has_trivial_copy(T); 190 #endif 191 }; 192 #else 193 template <class T> 194 using is_trivially_copyable = std::is_trivially_copyable<T>; 195 #endif 196 197 } // namespace base 198 199 #undef CR_USE_FALLBACKS_FOR_OLD_GLIBCXX 200 #undef CR_USE_FALLBACKS_FOR_GCC_WITH_LIBCXX 201 #undef CR_USE_FALLBACKS_FOR_OLD_EXPERIMENTAL_GLIBCXX 202 203 #endif // BASE_TEMPLATE_UTIL_H_ 204