1 //===- llvm/Support/type_traits.h - Simplfied type traits -------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 // This file provides useful additions to the standard type_traits library.
11 //===----------------------------------------------------------------------===//
13 #ifndef LLVM_SUPPORT_TYPE_TRAITS_H
14 #define LLVM_SUPPORT_TYPE_TRAITS_H
16 #include "llvm/Support/Compiler.h"
17 #include <type_traits>
23 /// Metafunction that determines whether the given type is either an
24 /// integral type or an enumeration type, including enum classes.
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 = std::remove_reference_t<T>;
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);
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 &; };
47 struct add_lvalue_reference_if_not_pointer<
48 T, std::enable_if_t<std::is_pointer<T>::value>> {
52 /// If T is a pointer to X, return a pointer to const X. If it is not,
54 template<typename T, typename Enable = void>
55 struct add_const_past_pointer { using type = const T; };
58 struct add_const_past_pointer<T, std::enable_if_t<std::is_pointer<T>::value>> {
59 using type = const std::remove_pointer_t<T> *;
62 template <typename T, typename Enable = void>
63 struct const_pointer_or_const_ref {
64 using type = const T &;
67 struct const_pointer_or_const_ref<T,
68 std::enable_if_t<std::is_pointer<T>::value>> {
69 using type = typename add_const_past_pointer<T>::type;
73 /// Internal utility to detect trivial copy construction.
74 template<typename T> union copy_construction_triviality_helper {
76 copy_construction_triviality_helper() = default;
77 copy_construction_triviality_helper(const copy_construction_triviality_helper&) = default;
78 ~copy_construction_triviality_helper() = default;
80 /// Internal utility to detect trivial move construction.
81 template<typename T> union move_construction_triviality_helper {
83 move_construction_triviality_helper() = default;
84 move_construction_triviality_helper(move_construction_triviality_helper&&) = default;
85 ~move_construction_triviality_helper() = default;
89 union trivial_helper {
93 } // end namespace detail
95 /// An implementation of `std::is_trivially_copy_constructible` since we have
96 /// users with STLs that don't yet include it.
98 struct is_trivially_copy_constructible
99 : std::is_copy_constructible<
100 ::llvm::detail::copy_construction_triviality_helper<T>> {};
101 template <typename T>
102 struct is_trivially_copy_constructible<T &> : std::true_type {};
103 template <typename T>
104 struct is_trivially_copy_constructible<T &&> : std::false_type {};
106 /// An implementation of `std::is_trivially_move_constructible` since we have
107 /// users with STLs that don't yet include it.
108 template <typename T>
109 struct is_trivially_move_constructible
110 : std::is_move_constructible<
111 ::llvm::detail::move_construction_triviality_helper<T>> {};
112 template <typename T>
113 struct is_trivially_move_constructible<T &> : std::true_type {};
114 template <typename T>
115 struct is_trivially_move_constructible<T &&> : std::true_type {};
118 template <typename T>
119 struct is_copy_assignable {
121 static auto get(F*) -> decltype(std::declval<F &>() = std::declval<const F &>(), std::true_type{});
122 static std::false_type get(...);
123 static constexpr bool value = decltype(get((T*)nullptr))::value;
126 template <typename T>
127 struct is_move_assignable {
129 static auto get(F*) -> decltype(std::declval<F &>() = std::declval<F &&>(), std::true_type{});
130 static std::false_type get(...);
131 static constexpr bool value = decltype(get((T*)nullptr))::value;
135 // An implementation of `std::is_trivially_copyable` since STL version
136 // is not equally supported by all compilers, especially GCC 4.9.
137 // Uniform implementation of this trait is important for ABI compatibility
138 // as it has an impact on SmallVector's ABI (among others).
139 template <typename T>
140 class is_trivially_copyable {
143 static constexpr bool has_trivial_copy_constructor =
144 std::is_copy_constructible<detail::trivial_helper<T>>::value;
145 static constexpr bool has_deleted_copy_constructor =
146 !std::is_copy_constructible<T>::value;
149 static constexpr bool has_trivial_move_constructor =
150 std::is_move_constructible<detail::trivial_helper<T>>::value;
151 static constexpr bool has_deleted_move_constructor =
152 !std::is_move_constructible<T>::value;
155 static constexpr bool has_trivial_copy_assign =
156 is_copy_assignable<detail::trivial_helper<T>>::value;
157 static constexpr bool has_deleted_copy_assign =
158 !is_copy_assignable<T>::value;
161 static constexpr bool has_trivial_move_assign =
162 is_move_assignable<detail::trivial_helper<T>>::value;
163 static constexpr bool has_deleted_move_assign =
164 !is_move_assignable<T>::value;
167 static constexpr bool has_trivial_destructor =
168 std::is_destructible<detail::trivial_helper<T>>::value;
172 static constexpr bool value =
173 has_trivial_destructor &&
174 (has_deleted_move_assign || has_trivial_move_assign) &&
175 (has_deleted_move_constructor || has_trivial_move_constructor) &&
176 (has_deleted_copy_assign || has_trivial_copy_assign) &&
177 (has_deleted_copy_constructor || has_trivial_copy_constructor);
179 #ifdef HAVE_STD_IS_TRIVIALLY_COPYABLE
180 static_assert(value == std::is_trivially_copyable<T>::value,
181 "inconsistent behavior between llvm:: and std:: implementation of is_trivially_copyable");
184 template <typename T>
185 class is_trivially_copyable<T*> : public std::true_type {
189 } // end namespace llvm
191 #endif // LLVM_SUPPORT_TYPE_TRAITS_H