#ifndef LIBAXX_LIBCXX_TYPE_TRAITS
#define LIBAXX_LIBCXX_TYPE_TRAITS

namespace std {

template <class _Tp> struct remove_const {typedef _Tp type;};
template <class _Tp> struct remove_const<const _Tp> {typedef _Tp type;};
template <class _Tp> struct remove_volatile {typedef _Tp type;};
template <class _Tp> struct remove_volatile<volatile _Tp> {typedef _Tp type;};
template <class _Tp> struct remove_cv {typedef typename remove_volatile<typename remove_const<_Tp>::type>::type type;};

template <class _Tp, _Tp __v>
struct integral_constant
{
    static constexpr const _Tp value = __v;
    typedef _Tp value_type;
    typedef integral_constant type;
    inline constexpr operator value_type() const noexcept {return value;}
};

typedef integral_constant<bool,(true)> true_type;
typedef integral_constant<bool,(false)> false_type;

// is_integral

template <class _Tp> struct __libcpp_is_integral : public false_type {};
template <>          struct __libcpp_is_integral<bool>               : public true_type {};
template <>          struct __libcpp_is_integral<char>               : public true_type {};
template <>          struct __libcpp_is_integral<signed char>        : public true_type {};
template <>          struct __libcpp_is_integral<unsigned char>      : public true_type {};
template <>          struct __libcpp_is_integral<wchar_t>            : public true_type {};
template <>          struct __libcpp_is_integral<short>              : public true_type {};
template <>          struct __libcpp_is_integral<unsigned short>     : public true_type {};
template <>          struct __libcpp_is_integral<int>                : public true_type {};
template <>          struct __libcpp_is_integral<unsigned int>       : public true_type {};
template <>          struct __libcpp_is_integral<long>               : public true_type {};
template <>          struct __libcpp_is_integral<unsigned long>      : public true_type {};
template <>          struct __libcpp_is_integral<long long>          : public true_type {};
template <>          struct __libcpp_is_integral<unsigned long long> : public true_type {};

template <class _Tp> struct is_integral : public __libcpp_is_integral<typename remove_cv<_Tp>::type> {};

// is_floating_point

template <class _Tp> struct __libcpp_is_floating_point : public false_type {};
template <> struct __libcpp_is_floating_point<float> : public true_type {};
template <> struct __libcpp_is_floating_point<double> : public true_type {};

template <class _Tp> struct is_floating_point : public __libcpp_is_floating_point<typename remove_cv<_Tp>::type> {};

// enable_if

template <bool, class _Tp = void> struct enable_if {};
template <class _Tp> struct _LIBCPP_TEMPLATE_VIS enable_if<true, _Tp> {typedef _Tp type;};

// is_same

template <class _Tp, class _Up> struct is_same : public false_type {};
template <class _Tp> struct is_same<_Tp, _Tp> : public true_type {};

// declval

template <class _Tp> struct add_rvalue_reference {typedef _Tp&& type;};
template <> struct add_rvalue_reference<void> {typedef void type;};
template <> struct add_rvalue_reference<const void> {typedef const void type;};
template <> struct add_rvalue_reference<volatile void> {typedef volatile void type;};
template <> struct add_rvalue_reference<const volatile void> {typedef const volatile void type;};
template <class _Tp> typename add_rvalue_reference<_Tp>::type declval() noexcept;

//__numeric_type

template <class _Tp>
struct __numeric_type
{
   static void __test(...);
   static float __test(float);
   static double __test(char);
   static double __test(int);
   static double __test(unsigned);
   static double __test(long);
   static double __test(unsigned long);
   static double __test(long long);
   static double __test(unsigned long long);
   static double __test(double);

   typedef decltype(__test(declval<_Tp>())) type;
   static const bool value = !is_same<type, void>::value;
};

template <>
struct __numeric_type<void>
{
   static const bool value = true;
};

// __promote

template <class _A1, class _A2 = void, class _A3 = void,
          bool = __numeric_type<_A1>::value &&
                 __numeric_type<_A2>::value &&
                 __numeric_type<_A3>::value>
class __promote_imp
{
public:
    static const bool value = false;
};

template <class _A1, class _A2, class _A3>
class __promote_imp<_A1, _A2, _A3, true>
{
private:
    typedef typename __promote_imp<_A1>::type __type1;
    typedef typename __promote_imp<_A2>::type __type2;
    typedef typename __promote_imp<_A3>::type __type3;
public:
    typedef decltype(__type1() + __type2() + __type3()) type;
    static const bool value = true;
};

template <class _A1, class _A2>
class __promote_imp<_A1, _A2, void, true>
{
private:
    typedef typename __promote_imp<_A1>::type __type1;
    typedef typename __promote_imp<_A2>::type __type2;
public:
    typedef decltype(__type1() + __type2()) type;
    static const bool value = true;
};

template <class _A1>
class __promote_imp<_A1, void, void, true>
{
public:
    typedef typename __numeric_type<_A1>::type type;
    static const bool value = true;
};

template <class _A1, class _A2 = void, class _A3 = void>
class __promote : public __promote_imp<_A1, _A2, _A3> {};

// is_arithmetic

template <class _Tp> struct is_arithmetic : public integral_constant<bool, is_integral<_Tp>::value || is_floating_point<_Tp>::value> {};

}
#endif
