| 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 |  | 
|---|