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>
34using std::pair;
35using std::make_pair;
36 // For pair
37
38namespace base {
39
40template <class T> struct is_integral;
41template <class T> struct is_floating_point;
42template <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.
46template <class T> struct is_enum;
47#endif
48template <class T> struct is_reference;
49template <class T> struct is_pod;
50template <class T> struct has_trivial_constructor;
51template <class T> struct has_trivial_copy;
52template <class T> struct has_trivial_assign;
53template <class T> struct has_trivial_destructor;
54template <class T> struct remove_const;
55template <class T> struct remove_volatile;
56template <class T> struct remove_cv;
57template <class T> struct remove_reference;
58template <class T> struct add_reference;
59template <class T> struct remove_pointer;
60template <class T, class U> struct is_same;
61#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3)
62template <class From, class To> struct is_convertible;
63#endif
64
65// is_integral is false except for the built-in integer types.
66template <class T> struct is_integral : false_type { };
67template<> struct is_integral<bool> : true_type { };
68template<> struct is_integral<char> : true_type { };
69template<> struct is_integral<unsigned char> : true_type { };
70template<> 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
75template<> struct is_integral<__wchar_t> : true_type { };
76#else
77template<> struct is_integral<wchar_t> : true_type { };
78#endif
79template<> struct is_integral<short> : true_type { };
80template<> struct is_integral<unsigned short> : true_type { };
81template<> struct is_integral<int> : true_type { };
82template<> struct is_integral<unsigned int> : true_type { };
83template<> struct is_integral<long> : true_type { };
84template<> struct is_integral<unsigned long> : true_type { };
85template<> struct is_integral<long long> : true_type { };
86template<> struct is_integral<unsigned long long> : true_type { };
87
88
89// is_floating_point is false except for the built-in floating-point types.
90template <class T> struct is_floating_point : false_type { };
91template<> struct is_floating_point<float> : true_type { };
92template<> struct is_floating_point<double> : true_type { };
93template<> struct is_floating_point<long double> : true_type { };
94
95
96// is_pointer is false except for pointer types.
97template <class T> struct is_pointer : false_type { };
98template <class T> struct is_pointer<T*> : true_type { };
99
100#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3)
101
102namespace internal {
103
104template <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.
112template <bool NotUnum, class T> struct is_enum_impl
113 : is_convertible<typename add_reference<T>::type, int> { };
114
115template <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).
133template <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
142template <class T> struct is_enum<const T> : is_enum<T> { };
143template <class T> struct is_enum<volatile T> : is_enum<T> { };
144template <class T> struct is_enum<const volatile T> : is_enum<T> { };
145
146#endif
147
148// is_reference is false except for reference types.
149template<typename T> struct is_reference : false_type {};
150template<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.
156template <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)> { };
164template <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.
172template <class T> struct has_trivial_constructor : is_pod<T> { };
173template <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)> { };
177template <class A, int N> struct has_trivial_constructor<A[N]>
178 : has_trivial_constructor<A> { };
179template <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.
187template <class T> struct has_trivial_copy : is_pod<T> { };
188template <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)> { };
192template <class A, int N> struct has_trivial_copy<A[N]>
193 : has_trivial_copy<A> { };
194template <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.
200template <class T> struct has_trivial_assign : is_pod<T> { };
201template <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)> { };
205template <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.
213template <class T> struct has_trivial_destructor : is_pod<T> { };
214template <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)> { };
218template <class A, int N> struct has_trivial_destructor<A[N]>
219 : has_trivial_destructor<A> { };
220template <class T> struct has_trivial_destructor<const T>
221 : has_trivial_destructor<T> { };
222
223// Specified by TR1 [4.7.1]
224template<typename T> struct remove_const { typedef T type; };
225template<typename T> struct remove_const<T const> { typedef T type; };
226template<typename T> struct remove_volatile { typedef T type; };
227template<typename T> struct remove_volatile<T volatile> { typedef T type; };
228template<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.
234template<typename T> struct remove_reference { typedef T type; };
235template<typename T> struct remove_reference<T&> { typedef T type; };
236
237template <typename T> struct add_reference { typedef T& type; };
238template <typename T> struct add_reference<T&> { typedef T& type; };
239
240// Specified by TR1 [4.7.4] Pointer modifications.
241template<typename T> struct remove_pointer { typedef T type; };
242template<typename T> struct remove_pointer<T*> { typedef T type; };
243template<typename T> struct remove_pointer<T* const> { typedef T type; };
244template<typename T> struct remove_pointer<T* volatile> { typedef T type; };
245template<typename T> struct remove_pointer<T* const volatile> {
246 typedef T type; };
247
248// Specified by TR1 [4.6] Relationships between types
249template<typename T, typename U> struct is_same : public false_type { };
250template<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)
254namespace 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
265template <typename From, typename To>
266struct 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.
274template <typename From, typename To>
275struct 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