1 // Copyright (c) 2006, Google Inc. 2 // All rights reserved. 3 // 4 // Redistribution and use in source and binary forms, with or without 5 // modification, are permitted provided that the following conditions are 6 // met: 7 // 8 // * Redistributions of source code must retain the above copyright 9 // notice, this list of conditions and the following disclaimer. 10 // * Redistributions in binary form must reproduce the above 11 // copyright notice, this list of conditions and the following disclaimer 12 // in the documentation and/or other materials provided with the 13 // distribution. 14 // * Neither the name of Google Inc. nor the names of its 15 // contributors may be used to endorse or promote products derived from 16 // this software without specific prior written permission. 17 // 18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 30 // ---- 31 // Author: Matt Austern 32 // 33 // This code is compiled directly on many platforms, including client 34 // platforms like Windows, Mac, and embedded systems. Before making 35 // any changes here, make sure that you're not breaking any platforms. 36 // 37 // Define a small subset of tr1 type traits. The traits we define are: 38 // is_integral 39 // is_floating_point 40 // is_pointer 41 // is_enum 42 // is_reference 43 // is_pod 44 // has_trivial_constructor 45 // has_trivial_copy 46 // has_trivial_assign 47 // has_trivial_destructor 48 // remove_const 49 // remove_volatile 50 // remove_cv 51 // remove_reference 52 // add_reference 53 // remove_pointer 54 // is_same 55 // is_convertible 56 // We can add more type traits as required. 57 58 #ifndef GOOGLE_PROTOBUF_TYPE_TRAITS_H_ 59 #define GOOGLE_PROTOBUF_TYPE_TRAITS_H_ 60 61 #include <utility> // For pair 62 63 #include <google/protobuf/stubs/template_util.h> // For true_type and false_type 64 65 namespace google { 66 namespace protobuf { 67 namespace internal { 68 69 template <class T> struct is_integral; 70 template <class T> struct is_floating_point; 71 template <class T> struct is_pointer; 72 // MSVC can't compile this correctly, and neither can gcc 3.3.5 (at least) 73 #if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3) 74 // is_enum uses is_convertible, which is not available on MSVC. 75 template <class T> struct is_enum; 76 #endif 77 template <class T> struct is_reference; 78 template <class T> struct is_pod; 79 template <class T> struct has_trivial_constructor; 80 template <class T> struct has_trivial_copy; 81 template <class T> struct has_trivial_assign; 82 template <class T> struct has_trivial_destructor; 83 template <class T> struct remove_const; 84 template <class T> struct remove_volatile; 85 template <class T> struct remove_cv; 86 template <class T> struct remove_reference; 87 template <class T> struct add_reference; 88 template <class T> struct remove_pointer; 89 template <class T, class U> struct is_same; 90 #if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3) 91 template <class From, class To> struct is_convertible; 92 #endif 93 94 // is_integral is false except for the built-in integer types. A 95 // cv-qualified type is integral if and only if the underlying type is. 96 template <class T> struct is_integral : false_type { }; 97 template<> struct is_integral<bool> : true_type { }; 98 template<> struct is_integral<char> : true_type { }; 99 template<> struct is_integral<unsigned char> : true_type { }; 100 template<> struct is_integral<signed char> : true_type { }; 101 #if defined(_MSC_VER) 102 // wchar_t is not by default a distinct type from unsigned short in 103 // Microsoft C. 104 // See http://msdn2.microsoft.com/en-us/library/dh8che7s(VS.80).aspx 105 template<> struct is_integral<__wchar_t> : true_type { }; 106 #else 107 template<> struct is_integral<wchar_t> : true_type { }; 108 #endif 109 template<> struct is_integral<short> : true_type { }; 110 template<> struct is_integral<unsigned short> : true_type { }; 111 template<> struct is_integral<int> : true_type { }; 112 template<> struct is_integral<unsigned int> : true_type { }; 113 template<> struct is_integral<long> : true_type { }; 114 template<> struct is_integral<unsigned long> : true_type { }; 115 #ifdef HAVE_LONG_LONG 116 template<> struct is_integral<long long> : true_type { }; 117 template<> struct is_integral<unsigned long long> : true_type { }; 118 #endif 119 template <class T> struct is_integral<const T> : is_integral<T> { }; 120 template <class T> struct is_integral<volatile T> : is_integral<T> { }; 121 template <class T> struct is_integral<const volatile T> : is_integral<T> { }; 122 123 // is_floating_point is false except for the built-in floating-point types. 124 // A cv-qualified type is integral if and only if the underlying type is. 125 template <class T> struct is_floating_point : false_type { }; 126 template<> struct is_floating_point<float> : true_type { }; 127 template<> struct is_floating_point<double> : true_type { }; 128 template<> struct is_floating_point<long double> : true_type { }; 129 template <class T> struct is_floating_point<const T> 130 : is_floating_point<T> { }; 131 template <class T> struct is_floating_point<volatile T> 132 : is_floating_point<T> { }; 133 template <class T> struct is_floating_point<const volatile T> 134 : is_floating_point<T> { }; 135 136 // is_pointer is false except for pointer types. A cv-qualified type (e.g. 137 // "int* const", as opposed to "int const*") is cv-qualified if and only if 138 // the underlying type is. 139 template <class T> struct is_pointer : false_type { }; 140 template <class T> struct is_pointer<T*> : true_type { }; 141 template <class T> struct is_pointer<const T> : is_pointer<T> { }; 142 template <class T> struct is_pointer<volatile T> : is_pointer<T> { }; 143 template <class T> struct is_pointer<const volatile T> : is_pointer<T> { }; 144 145 #if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3) 146 147 namespace internal { 148 149 template <class T> struct is_class_or_union { 150 template <class U> static small_ tester(void (U::*)()); 151 template <class U> static big_ tester(...); 152 static const bool value = sizeof(tester<T>(0)) == sizeof(small_); 153 }; 154 155 // is_convertible chokes if the first argument is an array. That's why 156 // we use add_reference here. 157 template <bool NotUnum, class T> struct is_enum_impl 158 : is_convertible<typename add_reference<T>::type, int> { }; 159 160 template <class T> struct is_enum_impl<true, T> : false_type { }; 161 162 } // namespace internal 163 164 // Specified by TR1 [4.5.1] primary type categories. 165 166 // Implementation note: 167 // 168 // Each type is either void, integral, floating point, array, pointer, 169 // reference, member object pointer, member function pointer, enum, 170 // union or class. Out of these, only integral, floating point, reference, 171 // class and enum types are potentially convertible to int. Therefore, 172 // if a type is not a reference, integral, floating point or class and 173 // is convertible to int, it's a enum. Adding cv-qualification to a type 174 // does not change whether it's an enum. 175 // 176 // Is-convertible-to-int check is done only if all other checks pass, 177 // because it can't be used with some types (e.g. void or classes with 178 // inaccessible conversion operators). 179 template <class T> struct is_enum 180 : internal::is_enum_impl< 181 is_same<T, void>::value || 182 is_integral<T>::value || 183 is_floating_point<T>::value || 184 is_reference<T>::value || 185 internal::is_class_or_union<T>::value, 186 T> { }; 187 188 template <class T> struct is_enum<const T> : is_enum<T> { }; 189 template <class T> struct is_enum<volatile T> : is_enum<T> { }; 190 template <class T> struct is_enum<const volatile T> : is_enum<T> { }; 191 192 #endif 193 194 // is_reference is false except for reference types. 195 template<typename T> struct is_reference : false_type {}; 196 template<typename T> struct is_reference<T&> : true_type {}; 197 198 199 // We can't get is_pod right without compiler help, so fail conservatively. 200 // We will assume it's false except for arithmetic types, enumerations, 201 // pointers and cv-qualified versions thereof. Note that std::pair<T,U> 202 // is not a POD even if T and U are PODs. 203 template <class T> struct is_pod 204 : integral_constant<bool, (is_integral<T>::value || 205 is_floating_point<T>::value || 206 #if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3) 207 // is_enum is not available on MSVC. 208 is_enum<T>::value || 209 #endif 210 is_pointer<T>::value)> { }; 211 template <class T> struct is_pod<const T> : is_pod<T> { }; 212 template <class T> struct is_pod<volatile T> : is_pod<T> { }; 213 template <class T> struct is_pod<const volatile T> : is_pod<T> { }; 214 215 216 // We can't get has_trivial_constructor right without compiler help, so 217 // fail conservatively. We will assume it's false except for: (1) types 218 // for which is_pod is true. (2) std::pair of types with trivial 219 // constructors. (3) array of a type with a trivial constructor. 220 // (4) const versions thereof. 221 template <class T> struct has_trivial_constructor : is_pod<T> { }; 222 template <class T, class U> struct has_trivial_constructor<std::pair<T, U> > 223 : integral_constant<bool, 224 (has_trivial_constructor<T>::value && 225 has_trivial_constructor<U>::value)> { }; 226 template <class A, int N> struct has_trivial_constructor<A[N]> 227 : has_trivial_constructor<A> { }; 228 template <class T> struct has_trivial_constructor<const T> 229 : has_trivial_constructor<T> { }; 230 231 // We can't get has_trivial_copy right without compiler help, so fail 232 // conservatively. We will assume it's false except for: (1) types 233 // for which is_pod is true. (2) std::pair of types with trivial copy 234 // constructors. (3) array of a type with a trivial copy constructor. 235 // (4) const versions thereof. 236 template <class T> struct has_trivial_copy : is_pod<T> { }; 237 template <class T, class U> struct has_trivial_copy<std::pair<T, U> > 238 : integral_constant<bool, 239 (has_trivial_copy<T>::value && 240 has_trivial_copy<U>::value)> { }; 241 template <class A, int N> struct has_trivial_copy<A[N]> 242 : has_trivial_copy<A> { }; 243 template <class T> struct has_trivial_copy<const T> : has_trivial_copy<T> { }; 244 245 // We can't get has_trivial_assign right without compiler help, so fail 246 // conservatively. We will assume it's false except for: (1) types 247 // for which is_pod is true. (2) std::pair of types with trivial copy 248 // constructors. (3) array of a type with a trivial assign constructor. 249 template <class T> struct has_trivial_assign : is_pod<T> { }; 250 template <class T, class U> struct has_trivial_assign<std::pair<T, U> > 251 : integral_constant<bool, 252 (has_trivial_assign<T>::value && 253 has_trivial_assign<U>::value)> { }; 254 template <class A, int N> struct has_trivial_assign<A[N]> 255 : has_trivial_assign<A> { }; 256 257 // We can't get has_trivial_destructor right without compiler help, so 258 // fail conservatively. We will assume it's false except for: (1) types 259 // for which is_pod is true. (2) std::pair of types with trivial 260 // destructors. (3) array of a type with a trivial destructor. 261 // (4) const versions thereof. 262 template <class T> struct has_trivial_destructor : is_pod<T> { }; 263 template <class T, class U> struct has_trivial_destructor<std::pair<T, U> > 264 : integral_constant<bool, 265 (has_trivial_destructor<T>::value && 266 has_trivial_destructor<U>::value)> { }; 267 template <class A, int N> struct has_trivial_destructor<A[N]> 268 : has_trivial_destructor<A> { }; 269 template <class T> struct has_trivial_destructor<const T> 270 : has_trivial_destructor<T> { }; 271 272 // Specified by TR1 [4.7.1] 273 template<typename T> struct remove_const { typedef T type; }; 274 template<typename T> struct remove_const<T const> { typedef T type; }; 275 template<typename T> struct remove_volatile { typedef T type; }; 276 template<typename T> struct remove_volatile<T volatile> { typedef T type; }; 277 template<typename T> struct remove_cv { 278 typedef typename remove_const<typename remove_volatile<T>::type>::type type; 279 }; 280 281 282 // Specified by TR1 [4.7.2] Reference modifications. 283 template<typename T> struct remove_reference { typedef T type; }; 284 template<typename T> struct remove_reference<T&> { typedef T type; }; 285 286 template <typename T> struct add_reference { typedef T& type; }; 287 template <typename T> struct add_reference<T&> { typedef T& type; }; 288 289 // Specified by TR1 [4.7.4] Pointer modifications. 290 template<typename T> struct remove_pointer { typedef T type; }; 291 template<typename T> struct remove_pointer<T*> { typedef T type; }; 292 template<typename T> struct remove_pointer<T* const> { typedef T type; }; 293 template<typename T> struct remove_pointer<T* volatile> { typedef T type; }; 294 template<typename T> struct remove_pointer<T* const volatile> { 295 typedef T type; }; 296 297 // Specified by TR1 [4.6] Relationships between types 298 template<typename T, typename U> struct is_same : public false_type { }; 299 template<typename T> struct is_same<T, T> : public true_type { }; 300 301 // Specified by TR1 [4.6] Relationships between types 302 #if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3) 303 namespace internal { 304 305 // This class is an implementation detail for is_convertible, and you 306 // don't need to know how it works to use is_convertible. For those 307 // who care: we declare two different functions, one whose argument is 308 // of type To and one with a variadic argument list. We give them 309 // return types of different size, so we can use sizeof to trick the 310 // compiler into telling us which function it would have chosen if we 311 // had called it with an argument of type From. See Alexandrescu's 312 // _Modern C++ Design_ for more details on this sort of trick. 313 314 template <typename From, typename To> 315 struct ConvertHelper { 316 static small_ Test(To); 317 static big_ Test(...); 318 static From Create(); 319 }; 320 } // namespace internal 321 322 // Inherits from true_type if From is convertible to To, false_type otherwise. 323 template <typename From, typename To> 324 struct is_convertible 325 : integral_constant<bool, 326 sizeof(internal::ConvertHelper<From, To>::Test( 327 internal::ConvertHelper<From, To>::Create())) 328 == sizeof(small_)> { 329 }; 330 #endif 331 332 } // namespace internal 333 } // namespace protobuf 334 } // namespace google 335 336 #endif // GOOGLE_PROTOBUF_TYPE_TRAITS_H_ 337