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 // enable_if 39 // is_integral 40 // is_floating_point 41 // is_pointer 42 // is_enum 43 // is_reference 44 // is_pod 45 // has_trivial_constructor 46 // has_trivial_copy 47 // has_trivial_assign 48 // has_trivial_destructor 49 // remove_const 50 // remove_volatile 51 // remove_cv 52 // remove_reference 53 // add_reference 54 // remove_pointer 55 // is_same 56 // is_convertible 57 // We can add more type traits as required. 58 59 #ifndef GOOGLE_PROTOBUF_TYPE_TRAITS_H_ 60 #define GOOGLE_PROTOBUF_TYPE_TRAITS_H_ 61 62 #include <cstddef> // for NULL 63 #include <utility> // For pair 64 65 #include <google/protobuf/stubs/template_util.h> // For true_type and false_type 66 67 namespace google { 68 namespace protobuf { 69 namespace internal { 70 71 template<typename B, typename D> 72 struct is_base_of { 73 typedef char (&yes)[1]; 74 typedef char (&no)[2]; 75 76 // BEGIN GOOGLE LOCAL MODIFICATION -- check is a #define on Mac. 77 #undef check 78 // END GOOGLE LOCAL MODIFICATION 79 80 static yes check(const B*); 81 static no check(const void*); 82 83 enum { 84 value = sizeof(check(static_cast<const D*>(NULL))) == sizeof(yes), 85 }; 86 }; 87 88 template <bool cond, class T = void> struct enable_if; 89 template <class T> struct is_integral; 90 template <class T> struct is_floating_point; 91 template <class T> struct is_pointer; 92 // MSVC can't compile this correctly, and neither can gcc 3.3.5 (at least) 93 #if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3) 94 // is_enum uses is_convertible, which is not available on MSVC. 95 template <class T> struct is_enum; 96 #endif 97 template <class T> struct is_reference; 98 template <class T> struct is_pod; 99 template <class T> struct has_trivial_constructor; 100 template <class T> struct has_trivial_copy; 101 template <class T> struct has_trivial_assign; 102 template <class T> struct has_trivial_destructor; 103 template <class T> struct remove_const; 104 template <class T> struct remove_volatile; 105 template <class T> struct remove_cv; 106 template <class T> struct remove_reference; 107 template <class T> struct add_reference; 108 template <class T> struct remove_pointer; 109 template <class T, class U> struct is_same; 110 #if !(defined(__GNUC__) && __GNUC__ <= 3) 111 template <class From, class To> struct is_convertible; 112 #endif 113 114 // enable_if, equivalent semantics to c++11 std::enable_if, specifically: 115 // "If B is true, the member typedef type shall equal T; otherwise, there 116 // shall be no member typedef type." 117 // Specified by 20.9.7.6 [Other transformations] 118 119 template<bool cond, class T> struct enable_if { typedef T type; }; 120 template<class T> struct enable_if<false, T> {}; 121 // is_integral is false except for the built-in integer types. A 122 // cv-qualified type is integral if and only if the underlying type is. 123 template <class T> struct is_integral : false_type { }; 124 template<> struct is_integral<bool> : true_type { }; 125 template<> struct is_integral<char> : true_type { }; 126 template<> struct is_integral<unsigned char> : true_type { }; 127 template<> struct is_integral<signed char> : true_type { }; 128 #if defined(_MSC_VER) 129 // wchar_t is not by default a distinct type from unsigned short in 130 // Microsoft C. 131 // See http://msdn2.microsoft.com/en-us/library/dh8che7s(VS.80).aspx 132 template<> struct is_integral<__wchar_t> : true_type { }; 133 #else 134 template<> struct is_integral<wchar_t> : true_type { }; 135 #endif 136 template<> struct is_integral<short> : true_type { }; 137 template<> struct is_integral<unsigned short> : true_type { }; 138 template<> struct is_integral<int> : true_type { }; 139 template<> struct is_integral<unsigned int> : true_type { }; 140 template<> struct is_integral<long> : true_type { }; 141 template<> struct is_integral<unsigned long> : true_type { }; 142 #ifdef HAVE_LONG_LONG 143 template<> struct is_integral<long long> : true_type { }; 144 template<> struct is_integral<unsigned long long> : true_type { }; 145 #endif 146 template <class T> struct is_integral<const T> : is_integral<T> { }; 147 template <class T> struct is_integral<volatile T> : is_integral<T> { }; 148 template <class T> struct is_integral<const volatile T> : is_integral<T> { }; 149 150 // is_floating_point is false except for the built-in floating-point types. 151 // A cv-qualified type is integral if and only if the underlying type is. 152 template <class T> struct is_floating_point : false_type { }; 153 template<> struct is_floating_point<float> : true_type { }; 154 template<> struct is_floating_point<double> : true_type { }; 155 template<> struct is_floating_point<long double> : true_type { }; 156 template <class T> struct is_floating_point<const T> 157 : is_floating_point<T> { }; 158 template <class T> struct is_floating_point<volatile T> 159 : is_floating_point<T> { }; 160 template <class T> struct is_floating_point<const volatile T> 161 : is_floating_point<T> { }; 162 163 // is_pointer is false except for pointer types. A cv-qualified type (e.g. 164 // "int* const", as opposed to "int const*") is cv-qualified if and only if 165 // the underlying type is. 166 template <class T> struct is_pointer : false_type { }; 167 template <class T> struct is_pointer<T*> : true_type { }; 168 template <class T> struct is_pointer<const T> : is_pointer<T> { }; 169 template <class T> struct is_pointer<volatile T> : is_pointer<T> { }; 170 template <class T> struct is_pointer<const volatile T> : is_pointer<T> { }; 171 172 #if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3) 173 174 namespace type_traits_internal { 175 176 template <class T> struct is_class_or_union { 177 template <class U> static small_ tester(void (U::*)()); 178 template <class U> static big_ tester(...); 179 static const bool value = sizeof(tester<T>(0)) == sizeof(small_); 180 }; 181 182 // is_convertible chokes if the first argument is an array. That's why 183 // we use add_reference here. 184 template <bool NotUnum, class T> struct is_enum_impl 185 : is_convertible<typename add_reference<T>::type, int> { }; 186 187 template <class T> struct is_enum_impl<true, T> : false_type { }; 188 189 } // namespace type_traits_internal 190 191 // Specified by TR1 [4.5.1] primary type categories. 192 193 // Implementation note: 194 // 195 // Each type is either void, integral, floating point, array, pointer, 196 // reference, member object pointer, member function pointer, enum, 197 // union or class. Out of these, only integral, floating point, reference, 198 // class and enum types are potentially convertible to int. Therefore, 199 // if a type is not a reference, integral, floating point or class and 200 // is convertible to int, it's a enum. Adding cv-qualification to a type 201 // does not change whether it's an enum. 202 // 203 // Is-convertible-to-int check is done only if all other checks pass, 204 // because it can't be used with some types (e.g. void or classes with 205 // inaccessible conversion operators). 206 template <class T> struct is_enum 207 : type_traits_internal::is_enum_impl< 208 is_same<T, void>::value || 209 is_integral<T>::value || 210 is_floating_point<T>::value || 211 is_reference<T>::value || 212 type_traits_internal::is_class_or_union<T>::value, 213 T> { }; 214 215 template <class T> struct is_enum<const T> : is_enum<T> { }; 216 template <class T> struct is_enum<volatile T> : is_enum<T> { }; 217 template <class T> struct is_enum<const volatile T> : is_enum<T> { }; 218 219 #endif 220 221 // is_reference is false except for reference types. 222 template<typename T> struct is_reference : false_type {}; 223 template<typename T> struct is_reference<T&> : true_type {}; 224 225 226 // We can't get is_pod right without compiler help, so fail conservatively. 227 // We will assume it's false except for arithmetic types, enumerations, 228 // pointers and cv-qualified versions thereof. Note that std::pair<T,U> 229 // is not a POD even if T and U are PODs. 230 template <class T> struct is_pod 231 : integral_constant<bool, (is_integral<T>::value || 232 is_floating_point<T>::value || 233 #if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3) 234 // is_enum is not available on MSVC. 235 is_enum<T>::value || 236 #endif 237 is_pointer<T>::value)> { }; 238 template <class T> struct is_pod<const T> : is_pod<T> { }; 239 template <class T> struct is_pod<volatile T> : is_pod<T> { }; 240 template <class T> struct is_pod<const volatile T> : is_pod<T> { }; 241 242 243 // We can't get has_trivial_constructor right without compiler help, so 244 // fail conservatively. We will assume it's false except for: (1) types 245 // for which is_pod is true. (2) std::pair of types with trivial 246 // constructors. (3) array of a type with a trivial constructor. 247 // (4) const versions thereof. 248 template <class T> struct has_trivial_constructor : is_pod<T> { }; 249 template <class T, class U> struct has_trivial_constructor<std::pair<T, U> > 250 : integral_constant<bool, 251 (has_trivial_constructor<T>::value && 252 has_trivial_constructor<U>::value)> { }; 253 template <class A, int N> struct has_trivial_constructor<A[N]> 254 : has_trivial_constructor<A> { }; 255 template <class T> struct has_trivial_constructor<const T> 256 : has_trivial_constructor<T> { }; 257 258 // We can't get has_trivial_copy right without compiler help, so fail 259 // conservatively. We will assume it's false except for: (1) types 260 // for which is_pod is true. (2) std::pair of types with trivial copy 261 // constructors. (3) array of a type with a trivial copy constructor. 262 // (4) const versions thereof. 263 template <class T> struct has_trivial_copy : is_pod<T> { }; 264 template <class T, class U> struct has_trivial_copy<std::pair<T, U> > 265 : integral_constant<bool, 266 (has_trivial_copy<T>::value && 267 has_trivial_copy<U>::value)> { }; 268 template <class A, int N> struct has_trivial_copy<A[N]> 269 : has_trivial_copy<A> { }; 270 template <class T> struct has_trivial_copy<const T> : has_trivial_copy<T> { }; 271 272 // We can't get has_trivial_assign right without compiler help, so fail 273 // conservatively. We will assume it's false except for: (1) types 274 // for which is_pod is true. (2) std::pair of types with trivial copy 275 // constructors. (3) array of a type with a trivial assign constructor. 276 template <class T> struct has_trivial_assign : is_pod<T> { }; 277 template <class T, class U> struct has_trivial_assign<std::pair<T, U> > 278 : integral_constant<bool, 279 (has_trivial_assign<T>::value && 280 has_trivial_assign<U>::value)> { }; 281 template <class A, int N> struct has_trivial_assign<A[N]> 282 : has_trivial_assign<A> { }; 283 284 // We can't get has_trivial_destructor right without compiler help, so 285 // fail conservatively. We will assume it's false except for: (1) types 286 // for which is_pod is true. (2) std::pair of types with trivial 287 // destructors. (3) array of a type with a trivial destructor. 288 // (4) const versions thereof. 289 template <class T> struct has_trivial_destructor : is_pod<T> { }; 290 template <class T, class U> struct has_trivial_destructor<std::pair<T, U> > 291 : integral_constant<bool, 292 (has_trivial_destructor<T>::value && 293 has_trivial_destructor<U>::value)> { }; 294 template <class A, int N> struct has_trivial_destructor<A[N]> 295 : has_trivial_destructor<A> { }; 296 template <class T> struct has_trivial_destructor<const T> 297 : has_trivial_destructor<T> { }; 298 299 // Specified by TR1 [4.7.1] 300 template<typename T> struct remove_const { typedef T type; }; 301 template<typename T> struct remove_const<T const> { typedef T type; }; 302 template<typename T> struct remove_volatile { typedef T type; }; 303 template<typename T> struct remove_volatile<T volatile> { typedef T type; }; 304 template<typename T> struct remove_cv { 305 typedef typename remove_const<typename remove_volatile<T>::type>::type type; 306 }; 307 308 309 // Specified by TR1 [4.7.2] Reference modifications. 310 template<typename T> struct remove_reference { typedef T type; }; 311 template<typename T> struct remove_reference<T&> { typedef T type; }; 312 313 template <typename T> struct add_reference { typedef T& type; }; 314 template <typename T> struct add_reference<T&> { typedef T& type; }; 315 316 // Specified by TR1 [4.7.4] Pointer modifications. 317 template<typename T> struct remove_pointer { typedef T type; }; 318 template<typename T> struct remove_pointer<T*> { typedef T type; }; 319 template<typename T> struct remove_pointer<T* const> { typedef T type; }; 320 template<typename T> struct remove_pointer<T* volatile> { typedef T type; }; 321 template<typename T> struct remove_pointer<T* const volatile> { 322 typedef T type; }; 323 324 // Specified by TR1 [4.6] Relationships between types 325 template<typename T, typename U> struct is_same : public false_type { }; 326 template<typename T> struct is_same<T, T> : public true_type { }; 327 328 // Specified by TR1 [4.6] Relationships between types 329 #if !(defined(__GNUC__) && __GNUC__ <= 3) 330 namespace type_traits_internal { 331 332 // This class is an implementation detail for is_convertible, and you 333 // don't need to know how it works to use is_convertible. For those 334 // who care: we declare two different functions, one whose argument is 335 // of type To and one with a variadic argument list. We give them 336 // return types of different size, so we can use sizeof to trick the 337 // compiler into telling us which function it would have chosen if we 338 // had called it with an argument of type From. See Alexandrescu's 339 // _Modern C++ Design_ for more details on this sort of trick. 340 341 template <typename From, typename To> 342 struct ConvertHelper { 343 static small_ Test(To); 344 static big_ Test(...); 345 static From Create(); 346 enum { 347 value = sizeof(Test(Create())) == sizeof(small_) 348 }; 349 }; 350 } // namespace type_traits_internal 351 352 // Inherits from true_type if From is convertible to To, false_type otherwise. 353 template <typename From, typename To> 354 struct is_convertible 355 : integral_constant<bool, 356 type_traits_internal::ConvertHelper<From, To>::value> { 357 }; 358 #endif 359 360 } // namespace internal 361 } // namespace protobuf 362 } // namespace google 363 364 #endif // GOOGLE_PROTOBUF_TYPE_TRAITS_H_ 365