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