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 | #ifndef __has_feature |
21 | #define LLVM_DEFINED_HAS_FEATURE |
22 | #define __has_feature(x) 0 |
23 | #endif |
24 | |
25 | namespace llvm { |
26 | |
27 | |
28 | /// Metafunction that determines whether the given type is either an |
29 | /// integral type or an enumeration type, including enum classes. |
30 | /// |
31 | /// Note that this accepts potentially more integral types than is_integral |
32 | /// because it is based on being implicitly convertible to an integral type. |
33 | /// Also note that enum classes aren't implicitly convertible to integral types, |
34 | /// the value may therefore need to be explicitly converted before being used. |
35 | template <typename T> class is_integral_or_enum { |
36 | using UnderlyingT = typename std::remove_reference<T>::type; |
37 | |
38 | public: |
39 | static const bool value = |
40 | !std::is_class<UnderlyingT>::value && // Filter conversion operators. |
41 | !std::is_pointer<UnderlyingT>::value && |
42 | !std::is_floating_point<UnderlyingT>::value && |
43 | (std::is_enum<UnderlyingT>::value || |
44 | std::is_convertible<UnderlyingT, unsigned long long>::value); |
45 | }; |
46 | |
47 | /// If T is a pointer, just return it. If it is not, return T&. |
48 | template<typename T, typename Enable = void> |
49 | struct add_lvalue_reference_if_not_pointer { using type = T &; }; |
50 | |
51 | template <typename T> |
52 | struct add_lvalue_reference_if_not_pointer< |
53 | T, typename std::enable_if<std::is_pointer<T>::value>::type> { |
54 | using type = T; |
55 | }; |
56 | |
57 | /// If T is a pointer to X, return a pointer to const X. If it is not, |
58 | /// return const T. |
59 | template<typename T, typename Enable = void> |
60 | struct add_const_past_pointer { using type = const T; }; |
61 | |
62 | template <typename T> |
63 | struct add_const_past_pointer< |
64 | T, typename std::enable_if<std::is_pointer<T>::value>::type> { |
65 | using type = const typename std::remove_pointer<T>::type *; |
66 | }; |
67 | |
68 | template <typename T, typename Enable = void> |
69 | struct const_pointer_or_const_ref { |
70 | using type = const T &; |
71 | }; |
72 | template <typename T> |
73 | struct const_pointer_or_const_ref< |
74 | T, typename std::enable_if<std::is_pointer<T>::value>::type> { |
75 | using type = typename add_const_past_pointer<T>::type; |
76 | }; |
77 | |
78 | namespace detail { |
79 | /// Internal utility to detect trivial copy construction. |
80 | template<typename T> union copy_construction_triviality_helper { |
81 | T t; |
82 | copy_construction_triviality_helper() = default; |
83 | copy_construction_triviality_helper(const copy_construction_triviality_helper&) = default; |
84 | ~copy_construction_triviality_helper() = default; |
85 | }; |
86 | /// Internal utility to detect trivial move construction. |
87 | template<typename T> union move_construction_triviality_helper { |
88 | T t; |
89 | move_construction_triviality_helper() = default; |
90 | move_construction_triviality_helper(move_construction_triviality_helper&&) = default; |
91 | ~move_construction_triviality_helper() = default; |
92 | }; |
93 | |
94 | template<class T> |
95 | union trivial_helper { |
96 | T t; |
97 | }; |
98 | |
99 | } // end namespace detail |
100 | |
101 | /// An implementation of `std::is_trivially_copy_constructible` since we have |
102 | /// users with STLs that don't yet include it. |
103 | template <typename T> |
104 | struct is_trivially_copy_constructible |
105 | : std::is_copy_constructible< |
106 | ::llvm::detail::copy_construction_triviality_helper<T>> {}; |
107 | template <typename T> |
108 | struct is_trivially_copy_constructible<T &> : std::true_type {}; |
109 | template <typename T> |
110 | struct is_trivially_copy_constructible<T &&> : std::false_type {}; |
111 | |
112 | /// An implementation of `std::is_trivially_move_constructible` since we have |
113 | /// users with STLs that don't yet include it. |
114 | template <typename T> |
115 | struct is_trivially_move_constructible |
116 | : std::is_move_constructible< |
117 | ::llvm::detail::move_construction_triviality_helper<T>> {}; |
118 | template <typename T> |
119 | struct is_trivially_move_constructible<T &> : std::true_type {}; |
120 | template <typename T> |
121 | struct is_trivially_move_constructible<T &&> : std::true_type {}; |
122 | |
123 | |
124 | template <typename T> |
125 | struct is_copy_assignable { |
126 | template<class F> |
127 | static auto get(F*) -> decltype(std::declval<F &>() = std::declval<const F &>(), std::true_type{}); |
128 | static std::false_type get(...); |
129 | static constexpr bool value = decltype(get((T*)nullptr))::value; |
130 | }; |
131 | |
132 | template <typename T> |
133 | struct is_move_assignable { |
134 | template<class F> |
135 | static auto get(F*) -> decltype(std::declval<F &>() = std::declval<F &&>(), std::true_type{}); |
136 | static std::false_type get(...); |
137 | static constexpr bool value = decltype(get((T*)nullptr))::value; |
138 | }; |
139 | |
140 | |
141 | // An implementation of `std::is_trivially_copyable` since STL version |
142 | // is not equally supported by all compilers, especially GCC 4.9. |
143 | // Uniform implementation of this trait is important for ABI compatibility |
144 | // as it has an impact on SmallVector's ABI (among others). |
145 | template <typename T> |
146 | class is_trivially_copyable { |
147 | |
148 | // copy constructors |
149 | static constexpr bool has_trivial_copy_constructor = |
150 | std::is_copy_constructible<detail::trivial_helper<T>>::value; |
151 | static constexpr bool has_deleted_copy_constructor = |
152 | !std::is_copy_constructible<T>::value; |
153 | |
154 | // move constructors |
155 | static constexpr bool has_trivial_move_constructor = |
156 | std::is_move_constructible<detail::trivial_helper<T>>::value; |
157 | static constexpr bool has_deleted_move_constructor = |
158 | !std::is_move_constructible<T>::value; |
159 | |
160 | // copy assign |
161 | static constexpr bool has_trivial_copy_assign = |
162 | is_copy_assignable<detail::trivial_helper<T>>::value; |
163 | static constexpr bool has_deleted_copy_assign = |
164 | !is_copy_assignable<T>::value; |
165 | |
166 | // move assign |
167 | static constexpr bool has_trivial_move_assign = |
168 | is_move_assignable<detail::trivial_helper<T>>::value; |
169 | static constexpr bool has_deleted_move_assign = |
170 | !is_move_assignable<T>::value; |
171 | |
172 | // destructor |
173 | static constexpr bool has_trivial_destructor = |
174 | std::is_destructible<detail::trivial_helper<T>>::value; |
175 | |
176 | public: |
177 | |
178 | static constexpr bool value = |
179 | has_trivial_destructor && |
180 | (has_deleted_move_assign || has_trivial_move_assign) && |
181 | (has_deleted_move_constructor || has_trivial_move_constructor) && |
182 | (has_deleted_copy_assign || has_trivial_copy_assign) && |
183 | (has_deleted_copy_constructor || has_trivial_copy_constructor); |
184 | |
185 | #ifdef HAVE_STD_IS_TRIVIALLY_COPYABLE |
186 | static_assert(value == std::is_trivially_copyable<T>::value, |
187 | "inconsistent behavior between llvm:: and std:: implementation of is_trivially_copyable" ); |
188 | #endif |
189 | }; |
190 | template <typename T> |
191 | class is_trivially_copyable<T*> : public std::true_type { |
192 | }; |
193 | |
194 | |
195 | } // end namespace llvm |
196 | |
197 | // If the compiler supports detecting whether a class is final, define |
198 | // an LLVM_IS_FINAL macro. If it cannot be defined properly, this |
199 | // macro will be left undefined. |
200 | #if __cplusplus >= 201402L || defined(_MSC_VER) |
201 | #define LLVM_IS_FINAL(Ty) std::is_final<Ty>() |
202 | #elif __has_feature(is_final) || LLVM_GNUC_PREREQ(4, 7, 0) |
203 | #define LLVM_IS_FINAL(Ty) __is_final(Ty) |
204 | #endif |
205 | |
206 | #ifdef LLVM_DEFINED_HAS_FEATURE |
207 | #undef __has_feature |
208 | #endif |
209 | |
210 | #endif // LLVM_SUPPORT_TYPE_TRAITS_H |
211 | |