1 //===- llvm/Support/type_traits.h - Simplfied type traits -------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file provides useful additions to the standard type_traits library. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #ifndef LLVM_SUPPORT_TYPE_TRAITS_H 14 #define LLVM_SUPPORT_TYPE_TRAITS_H 15 16 #include "llvm/Support/Compiler.h" 17 #include <type_traits> 18 #include <utility> 19 20 namespace llvm { 21 22 23 /// Metafunction that determines whether the given type is either an 24 /// integral type or an enumeration type, including enum classes. 25 /// 26 /// Note that this accepts potentially more integral types than is_integral 27 /// because it is based on being implicitly convertible to an integral type. 28 /// Also note that enum classes aren't implicitly convertible to integral types, 29 /// the value may therefore need to be explicitly converted before being used. 30 template <typename T> class is_integral_or_enum { 31 using UnderlyingT = typename std::remove_reference<T>::type; 32 33 public: 34 static const bool value = 35 !std::is_class<UnderlyingT>::value && // Filter conversion operators. 36 !std::is_pointer<UnderlyingT>::value && 37 !std::is_floating_point<UnderlyingT>::value && 38 (std::is_enum<UnderlyingT>::value || 39 std::is_convertible<UnderlyingT, unsigned long long>::value); 40 }; 41 42 /// If T is a pointer, just return it. If it is not, return T&. 43 template<typename T, typename Enable = void> 44 struct add_lvalue_reference_if_not_pointer { using type = T &; }; 45 46 template <typename T> 47 struct add_lvalue_reference_if_not_pointer< 48 T, typename std::enable_if<std::is_pointer<T>::value>::type> { 49 using type = T; 50 }; 51 52 /// If T is a pointer to X, return a pointer to const X. If it is not, 53 /// return const T. 54 template<typename T, typename Enable = void> 55 struct add_const_past_pointer { using type = const T; }; 56 57 template <typename T> 58 struct add_const_past_pointer< 59 T, typename std::enable_if<std::is_pointer<T>::value>::type> { 60 using type = const typename std::remove_pointer<T>::type *; 61 }; 62 63 template <typename T, typename Enable = void> 64 struct const_pointer_or_const_ref { 65 using type = const T &; 66 }; 67 template <typename T> 68 struct const_pointer_or_const_ref< 69 T, typename std::enable_if<std::is_pointer<T>::value>::type> { 70 using type = typename add_const_past_pointer<T>::type; 71 }; 72 73 namespace detail { 74 /// Internal utility to detect trivial copy construction. 75 template<typename T> union copy_construction_triviality_helper { 76 T t; 77 copy_construction_triviality_helper() = default; 78 copy_construction_triviality_helper(const copy_construction_triviality_helper&) = default; 79 ~copy_construction_triviality_helper() = default; 80 }; 81 /// Internal utility to detect trivial move construction. 82 template<typename T> union move_construction_triviality_helper { 83 T t; 84 move_construction_triviality_helper() = default; 85 move_construction_triviality_helper(move_construction_triviality_helper&&) = default; 86 ~move_construction_triviality_helper() = default; 87 }; 88 89 template<class T> 90 union trivial_helper { 91 T t; 92 }; 93 94 } // end namespace detail 95 96 /// An implementation of `std::is_trivially_copy_constructible` since we have 97 /// users with STLs that don't yet include it. 98 template <typename T> 99 struct is_trivially_copy_constructible 100 : std::is_copy_constructible< 101 ::llvm::detail::copy_construction_triviality_helper<T>> {}; 102 template <typename T> 103 struct is_trivially_copy_constructible<T &> : std::true_type {}; 104 template <typename T> 105 struct is_trivially_copy_constructible<T &&> : std::false_type {}; 106 107 /// An implementation of `std::is_trivially_move_constructible` since we have 108 /// users with STLs that don't yet include it. 109 template <typename T> 110 struct is_trivially_move_constructible 111 : std::is_move_constructible< 112 ::llvm::detail::move_construction_triviality_helper<T>> {}; 113 template <typename T> 114 struct is_trivially_move_constructible<T &> : std::true_type {}; 115 template <typename T> 116 struct is_trivially_move_constructible<T &&> : std::true_type {}; 117 118 119 template <typename T> 120 struct is_copy_assignable { 121 template<class F> 122 static auto get(F*) -> decltype(std::declval<F &>() = std::declval<const F &>(), std::true_type{}); 123 static std::false_type get(...); 124 static constexpr bool value = decltype(get((T*)nullptr))::value; 125 }; 126 127 template <typename T> 128 struct is_move_assignable { 129 template<class F> 130 static auto get(F*) -> decltype(std::declval<F &>() = std::declval<F &&>(), std::true_type{}); 131 static std::false_type get(...); 132 static constexpr bool value = decltype(get((T*)nullptr))::value; 133 }; 134 135 136 // An implementation of `std::is_trivially_copyable` since STL version 137 // is not equally supported by all compilers, especially GCC 4.9. 138 // Uniform implementation of this trait is important for ABI compatibility 139 // as it has an impact on SmallVector's ABI (among others). 140 template <typename T> 141 class is_trivially_copyable { 142 143 // copy constructors 144 static constexpr bool has_trivial_copy_constructor = 145 std::is_copy_constructible<detail::trivial_helper<T>>::value; 146 static constexpr bool has_deleted_copy_constructor = 147 !std::is_copy_constructible<T>::value; 148 149 // move constructors 150 static constexpr bool has_trivial_move_constructor = 151 std::is_move_constructible<detail::trivial_helper<T>>::value; 152 static constexpr bool has_deleted_move_constructor = 153 !std::is_move_constructible<T>::value; 154 155 // copy assign 156 static constexpr bool has_trivial_copy_assign = 157 is_copy_assignable<detail::trivial_helper<T>>::value; 158 static constexpr bool has_deleted_copy_assign = 159 !is_copy_assignable<T>::value; 160 161 // move assign 162 static constexpr bool has_trivial_move_assign = 163 is_move_assignable<detail::trivial_helper<T>>::value; 164 static constexpr bool has_deleted_move_assign = 165 !is_move_assignable<T>::value; 166 167 // destructor 168 static constexpr bool has_trivial_destructor = 169 std::is_destructible<detail::trivial_helper<T>>::value; 170 171 public: 172 173 static constexpr bool value = 174 has_trivial_destructor && 175 (has_deleted_move_assign || has_trivial_move_assign) && 176 (has_deleted_move_constructor || has_trivial_move_constructor) && 177 (has_deleted_copy_assign || has_trivial_copy_assign) && 178 (has_deleted_copy_constructor || has_trivial_copy_constructor); 179 180 #ifdef HAVE_STD_IS_TRIVIALLY_COPYABLE 181 static_assert(value == std::is_trivially_copyable<T>::value, 182 "inconsistent behavior between llvm:: and std:: implementation of is_trivially_copyable"); 183 #endif 184 }; 185 template <typename T> 186 class is_trivially_copyable<T*> : public std::true_type { 187 }; 188 189 190 } // end namespace llvm 191 192 #endif // LLVM_SUPPORT_TYPE_TRAITS_H 193