1 | // Copyright 2006 Google Inc. All Rights Reserved. |
2 | // |
3 | // This code is compiled directly on many platforms, including client |
4 | // platforms like Windows, Mac, and embedded systems. Before making |
5 | // any changes here, make sure that you're not breaking any platforms. |
6 | // |
7 | // |
8 | // Define a small subset of tr1 type traits. The traits we define are: |
9 | // is_integral |
10 | // is_floating_point |
11 | // is_pointer |
12 | // is_enum |
13 | // is_reference |
14 | // is_pod |
15 | // has_trivial_constructor |
16 | // has_trivial_copy |
17 | // has_trivial_assign |
18 | // has_trivial_destructor |
19 | // remove_const |
20 | // remove_volatile |
21 | // remove_cv |
22 | // remove_reference |
23 | // add_reference |
24 | // remove_pointer |
25 | // is_same |
26 | // is_convertible |
27 | // We can add more type traits as required. |
28 | |
29 | #ifndef BASE_TYPE_TRAITS_H_ |
30 | #define BASE_TYPE_TRAITS_H_ |
31 | |
32 | #include "base/template_util.h" // For true_type and false_type |
33 | #include <utility> |
34 | using std::pair; |
35 | using std::make_pair; |
36 | // For pair |
37 | |
38 | namespace base { |
39 | |
40 | template <class T> struct is_integral; |
41 | template <class T> struct is_floating_point; |
42 | template <class T> struct is_pointer; |
43 | // MSVC can't compile this correctly, and neither can gcc 3.3.5 (at least) |
44 | #if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3) |
45 | // is_enum uses is_convertible, which is not available on MSVC. |
46 | template <class T> struct is_enum; |
47 | #endif |
48 | template <class T> struct is_reference; |
49 | template <class T> struct is_pod; |
50 | template <class T> struct has_trivial_constructor; |
51 | template <class T> struct has_trivial_copy; |
52 | template <class T> struct has_trivial_assign; |
53 | template <class T> struct has_trivial_destructor; |
54 | template <class T> struct remove_const; |
55 | template <class T> struct remove_volatile; |
56 | template <class T> struct remove_cv; |
57 | template <class T> struct remove_reference; |
58 | template <class T> struct add_reference; |
59 | template <class T> struct remove_pointer; |
60 | template <class T, class U> struct is_same; |
61 | #if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3) |
62 | template <class From, class To> struct is_convertible; |
63 | #endif |
64 | |
65 | // is_integral is false except for the built-in integer types. |
66 | template <class T> struct is_integral : false_type { }; |
67 | template<> struct is_integral<bool> : true_type { }; |
68 | template<> struct is_integral<char> : true_type { }; |
69 | template<> struct is_integral<unsigned char> : true_type { }; |
70 | template<> struct is_integral<signed char> : true_type { }; |
71 | #if defined(_MSC_VER) |
72 | // wchar_t is not by default a distinct type from unsigned short in |
73 | // Microsoft C. |
74 | // See http://msdn2.microsoft.com/en-us/library/dh8che7s(VS.80).aspx |
75 | template<> struct is_integral<__wchar_t> : true_type { }; |
76 | #else |
77 | template<> struct is_integral<wchar_t> : true_type { }; |
78 | #endif |
79 | template<> struct is_integral<short> : true_type { }; |
80 | template<> struct is_integral<unsigned short> : true_type { }; |
81 | template<> struct is_integral<int> : true_type { }; |
82 | template<> struct is_integral<unsigned int> : true_type { }; |
83 | template<> struct is_integral<long> : true_type { }; |
84 | template<> struct is_integral<unsigned long> : true_type { }; |
85 | template<> struct is_integral<long long> : true_type { }; |
86 | template<> struct is_integral<unsigned long long> : true_type { }; |
87 | |
88 | |
89 | // is_floating_point is false except for the built-in floating-point types. |
90 | template <class T> struct is_floating_point : false_type { }; |
91 | template<> struct is_floating_point<float> : true_type { }; |
92 | template<> struct is_floating_point<double> : true_type { }; |
93 | template<> struct is_floating_point<long double> : true_type { }; |
94 | |
95 | |
96 | // is_pointer is false except for pointer types. |
97 | template <class T> struct is_pointer : false_type { }; |
98 | template <class T> struct is_pointer<T*> : true_type { }; |
99 | |
100 | #if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3) |
101 | |
102 | namespace internal { |
103 | |
104 | template <class T> struct is_class_or_union { |
105 | template <class U> static small_ tester(void (U::*)()); |
106 | template <class U> static big_ tester(...); |
107 | static const bool value = sizeof(tester<T>(0)) == sizeof(small_); |
108 | }; |
109 | |
110 | // is_convertible chokes if the first argument is an array. That's why |
111 | // we use add_reference here. |
112 | template <bool NotUnum, class T> struct is_enum_impl |
113 | : is_convertible<typename add_reference<T>::type, int> { }; |
114 | |
115 | template <class T> struct is_enum_impl<true, T> : false_type { }; |
116 | |
117 | } // namespace internal |
118 | |
119 | // Specified by TR1 [4.5.1] primary type categories. |
120 | |
121 | // Implementation note: |
122 | // |
123 | // Each type is either void, integral, floating point, array, pointer, |
124 | // reference, member object pointer, member function pointer, enum, |
125 | // union or class. Out of these, only integral, floating point, reference, |
126 | // class and enum types are potentially convertible to int. Therefore, |
127 | // if a type is not a reference, integral, floating point or class and |
128 | // is convertible to int, it's a enum. |
129 | // |
130 | // Is-convertible-to-int check is done only if all other checks pass, |
131 | // because it can't be used with some types (e.g. void or classes with |
132 | // inaccessible conversion operators). |
133 | template <class T> struct is_enum |
134 | : internal::is_enum_impl< |
135 | is_same<T, void>::value || |
136 | is_integral<T>::value || |
137 | is_floating_point<T>::value || |
138 | is_reference<T>::value || |
139 | internal::is_class_or_union<T>::value, |
140 | T> { }; |
141 | |
142 | template <class T> struct is_enum<const T> : is_enum<T> { }; |
143 | template <class T> struct is_enum<volatile T> : is_enum<T> { }; |
144 | template <class T> struct is_enum<const volatile T> : is_enum<T> { }; |
145 | |
146 | #endif |
147 | |
148 | // is_reference is false except for reference types. |
149 | template<typename T> struct is_reference : false_type {}; |
150 | template<typename T> struct is_reference<T&> : true_type {}; |
151 | |
152 | |
153 | // We can't get is_pod right without compiler help, so fail conservatively. |
154 | // We will assume it's false except for arithmetic types, enumerations, |
155 | // pointers and const versions thereof. Note that std::pair is not a POD. |
156 | template <class T> struct is_pod |
157 | : integral_constant<bool, (is_integral<T>::value || |
158 | is_floating_point<T>::value || |
159 | #if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3) |
160 | // is_enum is not available on MSVC. |
161 | is_enum<T>::value || |
162 | #endif |
163 | is_pointer<T>::value)> { }; |
164 | template <class T> struct is_pod<const T> : is_pod<T> { }; |
165 | |
166 | |
167 | // We can't get has_trivial_constructor right without compiler help, so |
168 | // fail conservatively. We will assume it's false except for: (1) types |
169 | // for which is_pod is true. (2) std::pair of types with trivial |
170 | // constructors. (3) array of a type with a trivial constructor. |
171 | // (4) const versions thereof. |
172 | template <class T> struct has_trivial_constructor : is_pod<T> { }; |
173 | template <class T, class U> struct has_trivial_constructor<std::pair<T, U> > |
174 | : integral_constant<bool, |
175 | (has_trivial_constructor<T>::value && |
176 | has_trivial_constructor<U>::value)> { }; |
177 | template <class A, int N> struct has_trivial_constructor<A[N]> |
178 | : has_trivial_constructor<A> { }; |
179 | template <class T> struct has_trivial_constructor<const T> |
180 | : has_trivial_constructor<T> { }; |
181 | |
182 | // We can't get has_trivial_copy right without compiler help, so fail |
183 | // conservatively. We will assume it's false except for: (1) types |
184 | // for which is_pod is true. (2) std::pair of types with trivial copy |
185 | // constructors. (3) array of a type with a trivial copy constructor. |
186 | // (4) const versions thereof. |
187 | template <class T> struct has_trivial_copy : is_pod<T> { }; |
188 | template <class T, class U> struct has_trivial_copy<std::pair<T, U> > |
189 | : integral_constant<bool, |
190 | (has_trivial_copy<T>::value && |
191 | has_trivial_copy<U>::value)> { }; |
192 | template <class A, int N> struct has_trivial_copy<A[N]> |
193 | : has_trivial_copy<A> { }; |
194 | template <class T> struct has_trivial_copy<const T> : has_trivial_copy<T> { }; |
195 | |
196 | // We can't get has_trivial_assign right without compiler help, so fail |
197 | // conservatively. We will assume it's false except for: (1) types |
198 | // for which is_pod is true. (2) std::pair of types with trivial copy |
199 | // constructors. (3) array of a type with a trivial assign constructor. |
200 | template <class T> struct has_trivial_assign : is_pod<T> { }; |
201 | template <class T, class U> struct has_trivial_assign<std::pair<T, U> > |
202 | : integral_constant<bool, |
203 | (has_trivial_assign<T>::value && |
204 | has_trivial_assign<U>::value)> { }; |
205 | template <class A, int N> struct has_trivial_assign<A[N]> |
206 | : has_trivial_assign<A> { }; |
207 | |
208 | // We can't get has_trivial_destructor right without compiler help, so |
209 | // fail conservatively. We will assume it's false except for: (1) types |
210 | // for which is_pod is true. (2) std::pair of types with trivial |
211 | // destructors. (3) array of a type with a trivial destructor. |
212 | // (4) const versions thereof. |
213 | template <class T> struct has_trivial_destructor : is_pod<T> { }; |
214 | template <class T, class U> struct has_trivial_destructor<std::pair<T, U> > |
215 | : integral_constant<bool, |
216 | (has_trivial_destructor<T>::value && |
217 | has_trivial_destructor<U>::value)> { }; |
218 | template <class A, int N> struct has_trivial_destructor<A[N]> |
219 | : has_trivial_destructor<A> { }; |
220 | template <class T> struct has_trivial_destructor<const T> |
221 | : has_trivial_destructor<T> { }; |
222 | |
223 | // Specified by TR1 [4.7.1] |
224 | template<typename T> struct remove_const { typedef T type; }; |
225 | template<typename T> struct remove_const<T const> { typedef T type; }; |
226 | template<typename T> struct remove_volatile { typedef T type; }; |
227 | template<typename T> struct remove_volatile<T volatile> { typedef T type; }; |
228 | template<typename T> struct remove_cv { |
229 | typedef typename remove_const<typename remove_volatile<T>::type>::type type; |
230 | }; |
231 | |
232 | |
233 | // Specified by TR1 [4.7.2] Reference modifications. |
234 | template<typename T> struct remove_reference { typedef T type; }; |
235 | template<typename T> struct remove_reference<T&> { typedef T type; }; |
236 | |
237 | template <typename T> struct add_reference { typedef T& type; }; |
238 | template <typename T> struct add_reference<T&> { typedef T& type; }; |
239 | |
240 | // Specified by TR1 [4.7.4] Pointer modifications. |
241 | template<typename T> struct remove_pointer { typedef T type; }; |
242 | template<typename T> struct remove_pointer<T*> { typedef T type; }; |
243 | template<typename T> struct remove_pointer<T* const> { typedef T type; }; |
244 | template<typename T> struct remove_pointer<T* volatile> { typedef T type; }; |
245 | template<typename T> struct remove_pointer<T* const volatile> { |
246 | typedef T type; }; |
247 | |
248 | // Specified by TR1 [4.6] Relationships between types |
249 | template<typename T, typename U> struct is_same : public false_type { }; |
250 | template<typename T> struct is_same<T, T> : public true_type { }; |
251 | |
252 | // Specified by TR1 [4.6] Relationships between types |
253 | #if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3) |
254 | namespace internal { |
255 | |
256 | // This class is an implementation detail for is_convertible, and you |
257 | // don't need to know how it works to use is_convertible. For those |
258 | // who care: we declare two different functions, one whose argument is |
259 | // of type To and one with a variadic argument list. We give them |
260 | // return types of different size, so we can use sizeof to trick the |
261 | // compiler into telling us which function it would have chosen if we |
262 | // had called it with an argument of type From. See Alexandrescu's |
263 | // _Modern C++ Design_ for more details on this sort of trick. |
264 | |
265 | template <typename From, typename To> |
266 | struct ConvertHelper { |
267 | static small_ Test(To); |
268 | static big_ Test(...); |
269 | static From Create(); |
270 | }; |
271 | } // namespace internal |
272 | |
273 | // Inherits from true_type if From is convertible to To, false_type otherwise. |
274 | template <typename From, typename To> |
275 | struct is_convertible |
276 | : integral_constant<bool, |
277 | sizeof(internal::ConvertHelper<From, To>::Test( |
278 | internal::ConvertHelper<From, To>::Create())) |
279 | == sizeof(small_)> { |
280 | }; |
281 | #endif |
282 | |
283 | } // Close namespace base |
284 | |
285 | #endif // BASE_TYPE_TRAITS_H_ |
286 | |