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 65namespace google { 66namespace protobuf { 67namespace internal { 68 69template <class T> struct is_integral; 70template <class T> struct is_floating_point; 71template <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. 75template <class T> struct is_enum; 76#endif 77template <class T> struct is_reference; 78template <class T> struct is_pod; 79template <class T> struct has_trivial_constructor; 80template <class T> struct has_trivial_copy; 81template <class T> struct has_trivial_assign; 82template <class T> struct has_trivial_destructor; 83template <class T> struct remove_const; 84template <class T> struct remove_volatile; 85template <class T> struct remove_cv; 86template <class T> struct remove_reference; 87template <class T> struct add_reference; 88template <class T> struct remove_pointer; 89template <class T, class U> struct is_same; 90#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3) 91template <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. 96template <class T> struct is_integral : false_type { }; 97template<> struct is_integral<bool> : true_type { }; 98template<> struct is_integral<char> : true_type { }; 99template<> struct is_integral<unsigned char> : true_type { }; 100template<> 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 105template<> struct is_integral<__wchar_t> : true_type { }; 106#else 107template<> struct is_integral<wchar_t> : true_type { }; 108#endif 109template<> struct is_integral<short> : true_type { }; 110template<> struct is_integral<unsigned short> : true_type { }; 111template<> struct is_integral<int> : true_type { }; 112template<> struct is_integral<unsigned int> : true_type { }; 113template<> struct is_integral<long> : true_type { }; 114template<> struct is_integral<unsigned long> : true_type { }; 115#ifdef HAVE_LONG_LONG 116template<> struct is_integral<long long> : true_type { }; 117template<> struct is_integral<unsigned long long> : true_type { }; 118#endif 119template <class T> struct is_integral<const T> : is_integral<T> { }; 120template <class T> struct is_integral<volatile T> : is_integral<T> { }; 121template <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. 125template <class T> struct is_floating_point : false_type { }; 126template<> struct is_floating_point<float> : true_type { }; 127template<> struct is_floating_point<double> : true_type { }; 128template<> struct is_floating_point<long double> : true_type { }; 129template <class T> struct is_floating_point<const T> 130 : is_floating_point<T> { }; 131template <class T> struct is_floating_point<volatile T> 132 : is_floating_point<T> { }; 133template <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. 139template <class T> struct is_pointer : false_type { }; 140template <class T> struct is_pointer<T*> : true_type { }; 141template <class T> struct is_pointer<const T> : is_pointer<T> { }; 142template <class T> struct is_pointer<volatile T> : is_pointer<T> { }; 143template <class T> struct is_pointer<const volatile T> : is_pointer<T> { }; 144 145#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3) 146 147namespace internal { 148 149template <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. 157template <bool NotUnum, class T> struct is_enum_impl 158 : is_convertible<typename add_reference<T>::type, int> { }; 159 160template <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). 179template <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 188template <class T> struct is_enum<const T> : is_enum<T> { }; 189template <class T> struct is_enum<volatile T> : is_enum<T> { }; 190template <class T> struct is_enum<const volatile T> : is_enum<T> { }; 191 192#endif 193 194// is_reference is false except for reference types. 195template<typename T> struct is_reference : false_type {}; 196template<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. 203template <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)> { }; 211template <class T> struct is_pod<const T> : is_pod<T> { }; 212template <class T> struct is_pod<volatile T> : is_pod<T> { }; 213template <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. 221template <class T> struct has_trivial_constructor : is_pod<T> { }; 222template <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)> { }; 226template <class A, int N> struct has_trivial_constructor<A[N]> 227 : has_trivial_constructor<A> { }; 228template <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. 236template <class T> struct has_trivial_copy : is_pod<T> { }; 237template <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)> { }; 241template <class A, int N> struct has_trivial_copy<A[N]> 242 : has_trivial_copy<A> { }; 243template <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. 249template <class T> struct has_trivial_assign : is_pod<T> { }; 250template <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)> { }; 254template <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. 262template <class T> struct has_trivial_destructor : is_pod<T> { }; 263template <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)> { }; 267template <class A, int N> struct has_trivial_destructor<A[N]> 268 : has_trivial_destructor<A> { }; 269template <class T> struct has_trivial_destructor<const T> 270 : has_trivial_destructor<T> { }; 271 272// Specified by TR1 [4.7.1] 273template<typename T> struct remove_const { typedef T type; }; 274template<typename T> struct remove_const<T const> { typedef T type; }; 275template<typename T> struct remove_volatile { typedef T type; }; 276template<typename T> struct remove_volatile<T volatile> { typedef T type; }; 277template<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. 283template<typename T> struct remove_reference { typedef T type; }; 284template<typename T> struct remove_reference<T&> { typedef T type; }; 285 286template <typename T> struct add_reference { typedef T& type; }; 287template <typename T> struct add_reference<T&> { typedef T& type; }; 288 289// Specified by TR1 [4.7.4] Pointer modifications. 290template<typename T> struct remove_pointer { typedef T type; }; 291template<typename T> struct remove_pointer<T*> { typedef T type; }; 292template<typename T> struct remove_pointer<T* const> { typedef T type; }; 293template<typename T> struct remove_pointer<T* volatile> { typedef T type; }; 294template<typename T> struct remove_pointer<T* const volatile> { 295 typedef T type; }; 296 297// Specified by TR1 [4.6] Relationships between types 298template<typename T, typename U> struct is_same : public false_type { }; 299template<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) 303namespace 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 314template <typename From, typename To> 315struct 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. 323template <typename From, typename To> 324struct 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