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