1193323Sed//===- llvm/Support/type_traits.h - Simplfied type traits -------*- C++ -*-===//
2193323Sed//
3193323Sed//                     The LLVM Compiler Infrastructure
4193323Sed//
5193323Sed// This file is distributed under the University of Illinois Open Source
6193323Sed// License. See LICENSE.TXT for details.
7193323Sed//
8193323Sed//===----------------------------------------------------------------------===//
9193323Sed//
10193323Sed// This file provides a template class that determines if a type is a class or
11193323Sed// not. The basic mechanism, based on using the pointer to member function of
12193323Sed// a zero argument to a function was "boosted" from the boost type_traits
13193323Sed// library. See http://www.boost.org/ for all the gory details.
14193323Sed//
15193323Sed//===----------------------------------------------------------------------===//
16193323Sed
17193323Sed#ifndef LLVM_SUPPORT_TYPE_TRAITS_H
18193323Sed#define LLVM_SUPPORT_TYPE_TRAITS_H
19193323Sed
20234353Sdim#include "llvm/Support/DataTypes.h"
21234353Sdim#include <cstddef>
22200581Srdivacky#include <utility>
23200581Srdivacky
24239462Sdim#ifndef __has_feature
25239462Sdim#define LLVM_DEFINED_HAS_FEATURE
26239462Sdim#define __has_feature(x) 0
27239462Sdim#endif
28239462Sdim
29193323Sed// This is actually the conforming implementation which works with abstract
30193323Sed// classes.  However, enough compilers have trouble with it that most will use
31193323Sed// the one in boost/type_traits/object_traits.hpp. This implementation actually
32193323Sed// works with VC7.0, but other interactions seem to fail when we use it.
33193323Sed
34193323Sednamespace llvm {
35200581Srdivacky
36193323Sednamespace dont_use
37193323Sed{
38193323Sed    // These two functions should never be used. They are helpers to
39193323Sed    // the is_class template below. They cannot be located inside
40193323Sed    // is_class because doing so causes at least GCC to think that
41193323Sed    // the value of the "value" enumerator is not constant. Placing
42193323Sed    // them out here (for some strange reason) allows the sizeof
43193323Sed    // operator against them to magically be constant. This is
44193323Sed    // important to make the is_class<T>::value idiom zero cost. it
45193323Sed    // evaluates to a constant 1 or 0 depending on whether the
46193323Sed    // parameter T is a class or not (respectively).
47198090Srdivacky    template<typename T> char is_class_helper(void(T::*)());
48193323Sed    template<typename T> double is_class_helper(...);
49193323Sed}
50193323Sed
51193323Sedtemplate <typename T>
52193323Sedstruct is_class
53193323Sed{
54193323Sed  // is_class<> metafunction due to Paul Mensonides (leavings@attbi.com). For
55193323Sed  // more details:
56193323Sed  // http://groups.google.com/groups?hl=en&selm=000001c1cc83%24e154d5e0%247772e50c%40c161550a&rnum=1
57243830Sdimpublic:
58243830Sdim  static const bool value =
59243830Sdim      sizeof(char) == sizeof(dont_use::is_class_helper<T>(0));
60193323Sed};
61200581Srdivacky
62200581Srdivacky
63200581Srdivacky/// isPodLike - This is a type trait that is used to determine whether a given
64200581Srdivacky/// type can be copied around with memcpy instead of running ctors etc.
65200581Srdivackytemplate <typename T>
66200581Srdivackystruct isPodLike {
67239462Sdim#if __has_feature(is_trivially_copyable)
68239462Sdim  // If the compiler supports the is_trivially_copyable trait use it, as it
69239462Sdim  // matches the definition of isPodLike closely.
70239462Sdim  static const bool value = __is_trivially_copyable(T);
71239462Sdim#else
72200581Srdivacky  // If we don't know anything else, we can (at least) assume that all non-class
73200581Srdivacky  // types are PODs.
74200581Srdivacky  static const bool value = !is_class<T>::value;
75239462Sdim#endif
76200581Srdivacky};
77193323Sed
78200581Srdivacky// std::pair's are pod-like if their elements are.
79200581Srdivackytemplate<typename T, typename U>
80200581Srdivackystruct isPodLike<std::pair<T, U> > {
81234353Sdim  static const bool value = isPodLike<T>::value && isPodLike<U>::value;
82200581Srdivacky};
83200581Srdivacky
84200581Srdivacky
85234353Sdimtemplate <class T, T v>
86234353Sdimstruct integral_constant {
87234353Sdim  typedef T value_type;
88234353Sdim  static const value_type value = v;
89234353Sdim  typedef integral_constant<T,v> type;
90234353Sdim  operator value_type() { return value; }
91234353Sdim};
92234353Sdim
93234353Sdimtypedef integral_constant<bool, true> true_type;
94234353Sdimtypedef integral_constant<bool, false> false_type;
95234353Sdim
96198090Srdivacky/// \brief Metafunction that determines whether the two given types are
97198090Srdivacky/// equivalent.
98234353Sdimtemplate<typename T, typename U> struct is_same       : public false_type {};
99234353Sdimtemplate<typename T>             struct is_same<T, T> : public true_type {};
100234353Sdim
101234353Sdim/// \brief Metafunction that removes const qualification from a type.
102234353Sdimtemplate <typename T> struct remove_const          { typedef T type; };
103234353Sdimtemplate <typename T> struct remove_const<const T> { typedef T type; };
104234353Sdim
105234353Sdim/// \brief Metafunction that removes volatile qualification from a type.
106234353Sdimtemplate <typename T> struct remove_volatile             { typedef T type; };
107234353Sdimtemplate <typename T> struct remove_volatile<volatile T> { typedef T type; };
108234353Sdim
109234353Sdim/// \brief Metafunction that removes both const and volatile qualification from
110234353Sdim/// a type.
111234353Sdimtemplate <typename T> struct remove_cv {
112234353Sdim  typedef typename remove_const<typename remove_volatile<T>::type>::type type;
113198090Srdivacky};
114198090Srdivacky
115234353Sdim/// \brief Helper to implement is_integral metafunction.
116234353Sdimtemplate <typename T> struct is_integral_impl           : false_type {};
117234353Sdimtemplate <> struct is_integral_impl<         bool>      : true_type {};
118234353Sdimtemplate <> struct is_integral_impl<         char>      : true_type {};
119234353Sdimtemplate <> struct is_integral_impl<  signed char>      : true_type {};
120234353Sdimtemplate <> struct is_integral_impl<unsigned char>      : true_type {};
121234353Sdimtemplate <> struct is_integral_impl<         wchar_t>   : true_type {};
122234353Sdimtemplate <> struct is_integral_impl<         short>     : true_type {};
123234353Sdimtemplate <> struct is_integral_impl<unsigned short>     : true_type {};
124234353Sdimtemplate <> struct is_integral_impl<         int>       : true_type {};
125234353Sdimtemplate <> struct is_integral_impl<unsigned int>       : true_type {};
126234353Sdimtemplate <> struct is_integral_impl<         long>      : true_type {};
127234353Sdimtemplate <> struct is_integral_impl<unsigned long>      : true_type {};
128234353Sdimtemplate <> struct is_integral_impl<         long long> : true_type {};
129234353Sdimtemplate <> struct is_integral_impl<unsigned long long> : true_type {};
130234353Sdim
131234353Sdim/// \brief Metafunction that determines whether the given type is an integral
132234353Sdim/// type.
133234353Sdimtemplate <typename T>
134234353Sdimstruct is_integral : is_integral_impl<T> {};
135234353Sdim
136234353Sdim/// \brief Metafunction to remove reference from a type.
137234353Sdimtemplate <typename T> struct remove_reference { typedef T type; };
138234353Sdimtemplate <typename T> struct remove_reference<T&> { typedef T type; };
139234353Sdim
140234353Sdim/// \brief Metafunction that determines whether the given type is a pointer
141234353Sdim/// type.
142234353Sdimtemplate <typename T> struct is_pointer : false_type {};
143234353Sdimtemplate <typename T> struct is_pointer<T*> : true_type {};
144234353Sdimtemplate <typename T> struct is_pointer<T* const> : true_type {};
145234353Sdimtemplate <typename T> struct is_pointer<T* volatile> : true_type {};
146234353Sdimtemplate <typename T> struct is_pointer<T* const volatile> : true_type {};
147234353Sdim
148249423Sdim/// \brief Metafunction that determines wheather the given type is a reference.
149249423Sdimtemplate <typename T> struct is_reference : false_type {};
150249423Sdimtemplate <typename T> struct is_reference<T&> : true_type {};
151249423Sdim
152234353Sdim/// \brief Metafunction that determines whether the given type is either an
153234353Sdim/// integral type or an enumeration type.
154234353Sdim///
155234353Sdim/// Note that this accepts potentially more integral types than we whitelist
156234353Sdim/// above for is_integral because it is based on merely being convertible
157234353Sdim/// implicitly to an integral type.
158234353Sdimtemplate <typename T> class is_integral_or_enum {
159234353Sdim  // Provide an overload which can be called with anything implicitly
160234353Sdim  // convertible to an unsigned long long. This should catch integer types and
161234353Sdim  // enumeration types at least. We blacklist classes with conversion operators
162234353Sdim  // below.
163234353Sdim  static double check_int_convertible(unsigned long long);
164234353Sdim  static char check_int_convertible(...);
165234353Sdim
166234353Sdim  typedef typename remove_reference<T>::type UnderlyingT;
167234353Sdim  static UnderlyingT &nonce_instance;
168234353Sdim
169234353Sdimpublic:
170243830Sdim  static const bool
171234353Sdim    value = (!is_class<UnderlyingT>::value && !is_pointer<UnderlyingT>::value &&
172234353Sdim             !is_same<UnderlyingT, float>::value &&
173234353Sdim             !is_same<UnderlyingT, double>::value &&
174243830Sdim             sizeof(char) != sizeof(check_int_convertible(nonce_instance)));
175198090Srdivacky};
176234353Sdim
177198090Srdivacky// enable_if_c - Enable/disable a template based on a metafunction
178198090Srdivackytemplate<bool Cond, typename T = void>
179198090Srdivackystruct enable_if_c {
180198090Srdivacky  typedef T type;
181198090Srdivacky};
182198090Srdivacky
183198090Srdivackytemplate<typename T> struct enable_if_c<false, T> { };
184198090Srdivacky
185198090Srdivacky// enable_if - Enable/disable a template based on a metafunction
186198090Srdivackytemplate<typename Cond, typename T = void>
187198090Srdivackystruct enable_if : public enable_if_c<Cond::value, T> { };
188198090Srdivacky
189198090Srdivackynamespace dont_use {
190198090Srdivacky  template<typename Base> char base_of_helper(const volatile Base*);
191198090Srdivacky  template<typename Base> double base_of_helper(...);
192193323Sed}
193193323Sed
194198090Srdivacky/// is_base_of - Metafunction to determine whether one type is a base class of
195198090Srdivacky/// (or identical to) another type.
196198090Srdivackytemplate<typename Base, typename Derived>
197198090Srdivackystruct is_base_of {
198198090Srdivacky  static const bool value
199198090Srdivacky    = is_class<Base>::value && is_class<Derived>::value &&
200198090Srdivacky      sizeof(char) == sizeof(dont_use::base_of_helper<Base>((Derived*)0));
201198090Srdivacky};
202198090Srdivacky
203198396Srdivacky// remove_pointer - Metafunction to turn Foo* into Foo.  Defined in
204198396Srdivacky// C++0x [meta.trans.ptr].
205198396Srdivackytemplate <typename T> struct remove_pointer { typedef T type; };
206198396Srdivackytemplate <typename T> struct remove_pointer<T*> { typedef T type; };
207198396Srdivackytemplate <typename T> struct remove_pointer<T*const> { typedef T type; };
208198396Srdivackytemplate <typename T> struct remove_pointer<T*volatile> { typedef T type; };
209198396Srdivackytemplate <typename T> struct remove_pointer<T*const volatile> {
210198396Srdivacky    typedef T type; };
211198396Srdivacky
212249423Sdim// If T is a pointer, just return it. If it is not, return T&.
213249423Sdimtemplate<typename T, typename Enable = void>
214249423Sdimstruct add_lvalue_reference_if_not_pointer { typedef T &type; };
215249423Sdim
216249423Sdimtemplate<typename T>
217249423Sdimstruct add_lvalue_reference_if_not_pointer<T,
218249423Sdim                                     typename enable_if<is_pointer<T> >::type> {
219249423Sdim  typedef T type;
220249423Sdim};
221249423Sdim
222249423Sdim// If T is a pointer to X, return a pointer to const X. If it is not, return
223249423Sdim// const T.
224249423Sdimtemplate<typename T, typename Enable = void>
225249423Sdimstruct add_const_past_pointer { typedef const T type; };
226249423Sdim
227249423Sdimtemplate<typename T>
228249423Sdimstruct add_const_past_pointer<T, typename enable_if<is_pointer<T> >::type> {
229249423Sdim  typedef const typename remove_pointer<T>::type *type;
230249423Sdim};
231249423Sdim
232199481Srdivackytemplate <bool, typename T, typename F>
233199481Srdivackystruct conditional { typedef T type; };
234199481Srdivacky
235199481Srdivackytemplate <typename T, typename F>
236199481Srdivackystruct conditional<false, T, F> { typedef F type; };
237199481Srdivacky
238198090Srdivacky}
239198090Srdivacky
240239462Sdim#ifdef LLVM_DEFINED_HAS_FEATURE
241239462Sdim#undef __has_feature
242193323Sed#endif
243239462Sdim
244239462Sdim#endif
245