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