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