Home | History | Annotate | Download | only in stubs
      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