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