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 67namespace google { 68namespace protobuf { 69namespace internal { 70 71template<typename B, typename D> 72struct 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 88template <bool cond, class T = void> struct enable_if; 89template <class T> struct is_integral; 90template <class T> struct is_floating_point; 91template <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. 95template <class T> struct is_enum; 96#endif 97template <class T> struct is_reference; 98template <class T> struct is_pod; 99template <class T> struct has_trivial_constructor; 100template <class T> struct has_trivial_copy; 101template <class T> struct has_trivial_assign; 102template <class T> struct has_trivial_destructor; 103template <class T> struct remove_const; 104template <class T> struct remove_volatile; 105template <class T> struct remove_cv; 106template <class T> struct remove_reference; 107template <class T> struct add_reference; 108template <class T> struct remove_pointer; 109template <class T, class U> struct is_same; 110#if !(defined(__GNUC__) && __GNUC__ <= 3) 111template <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 119template<bool cond, class T> struct enable_if { typedef T type; }; 120template<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. 123template <class T> struct is_integral : false_type { }; 124template<> struct is_integral<bool> : true_type { }; 125template<> struct is_integral<char> : true_type { }; 126template<> struct is_integral<unsigned char> : true_type { }; 127template<> 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 132template<> struct is_integral<__wchar_t> : true_type { }; 133#else 134template<> struct is_integral<wchar_t> : true_type { }; 135#endif 136template<> struct is_integral<short> : true_type { }; 137template<> struct is_integral<unsigned short> : true_type { }; 138template<> struct is_integral<int> : true_type { }; 139template<> struct is_integral<unsigned int> : true_type { }; 140template<> struct is_integral<long> : true_type { }; 141template<> struct is_integral<unsigned long> : true_type { }; 142#ifdef HAVE_LONG_LONG 143template<> struct is_integral<long long> : true_type { }; 144template<> struct is_integral<unsigned long long> : true_type { }; 145#endif 146template <class T> struct is_integral<const T> : is_integral<T> { }; 147template <class T> struct is_integral<volatile T> : is_integral<T> { }; 148template <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. 152template <class T> struct is_floating_point : false_type { }; 153template<> struct is_floating_point<float> : true_type { }; 154template<> struct is_floating_point<double> : true_type { }; 155template<> struct is_floating_point<long double> : true_type { }; 156template <class T> struct is_floating_point<const T> 157 : is_floating_point<T> { }; 158template <class T> struct is_floating_point<volatile T> 159 : is_floating_point<T> { }; 160template <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. 166template <class T> struct is_pointer : false_type { }; 167template <class T> struct is_pointer<T*> : true_type { }; 168template <class T> struct is_pointer<const T> : is_pointer<T> { }; 169template <class T> struct is_pointer<volatile T> : is_pointer<T> { }; 170template <class T> struct is_pointer<const volatile T> : is_pointer<T> { }; 171 172#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3) 173 174namespace type_traits_internal { 175 176template <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. 184template <bool NotUnum, class T> struct is_enum_impl 185 : is_convertible<typename add_reference<T>::type, int> { }; 186 187template <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). 206template <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 215template <class T> struct is_enum<const T> : is_enum<T> { }; 216template <class T> struct is_enum<volatile T> : is_enum<T> { }; 217template <class T> struct is_enum<const volatile T> : is_enum<T> { }; 218 219#endif 220 221// is_reference is false except for reference types. 222template<typename T> struct is_reference : false_type {}; 223template<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. 230template <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)> { }; 238template <class T> struct is_pod<const T> : is_pod<T> { }; 239template <class T> struct is_pod<volatile T> : is_pod<T> { }; 240template <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. 248template <class T> struct has_trivial_constructor : is_pod<T> { }; 249template <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)> { }; 253template <class A, int N> struct has_trivial_constructor<A[N]> 254 : has_trivial_constructor<A> { }; 255template <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. 263template <class T> struct has_trivial_copy : is_pod<T> { }; 264template <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)> { }; 268template <class A, int N> struct has_trivial_copy<A[N]> 269 : has_trivial_copy<A> { }; 270template <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. 276template <class T> struct has_trivial_assign : is_pod<T> { }; 277template <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)> { }; 281template <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. 289template <class T> struct has_trivial_destructor : is_pod<T> { }; 290template <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)> { }; 294template <class A, int N> struct has_trivial_destructor<A[N]> 295 : has_trivial_destructor<A> { }; 296template <class T> struct has_trivial_destructor<const T> 297 : has_trivial_destructor<T> { }; 298 299// Specified by TR1 [4.7.1] 300template<typename T> struct remove_const { typedef T type; }; 301template<typename T> struct remove_const<T const> { typedef T type; }; 302template<typename T> struct remove_volatile { typedef T type; }; 303template<typename T> struct remove_volatile<T volatile> { typedef T type; }; 304template<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. 310template<typename T> struct remove_reference { typedef T type; }; 311template<typename T> struct remove_reference<T&> { typedef T type; }; 312 313template <typename T> struct add_reference { typedef T& type; }; 314template <typename T> struct add_reference<T&> { typedef T& type; }; 315 316// Specified by TR1 [4.7.4] Pointer modifications. 317template<typename T> struct remove_pointer { typedef T type; }; 318template<typename T> struct remove_pointer<T*> { typedef T type; }; 319template<typename T> struct remove_pointer<T* const> { typedef T type; }; 320template<typename T> struct remove_pointer<T* volatile> { typedef T type; }; 321template<typename T> struct remove_pointer<T* const volatile> { 322 typedef T type; }; 323 324// Specified by TR1 [4.6] Relationships between types 325template<typename T, typename U> struct is_same : public false_type { }; 326template<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) 330namespace 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 341template <typename From, typename To> 342struct 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. 353template <typename From, typename To> 354struct 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