/* Copyright 2018 kevin Lau (http://github.com/stormycatcat)

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#ifndef _STDLIB_TYPE_TRAITS_
#define _STDLIB_TYPE_TRAITS_

#include <cstddef>

namespace std
{

template<class... >
using void_t=void;


template<class T>
struct add_lvalue_reference
{
    using type=T&;
};

template<class T>
struct add_lvalue_reference<T&>
{
    using type=T&;
};

template<class T>
struct add_rvalue_reference
{
    using type=T&&;
};

template<class T>
struct add_rvalue_reference<T&&>
{
    using type=T&&;
};


template<class T>
struct remove_const
{
    using type=T;
};

template<class T>
struct remove_const<const T>
{
    using type=T;
};

template<class T>
struct remove_volatile
{
    using type=T;
};

template<class T>
struct remove_volatile<volatile T>
{
    using type=T;
};

template<class T>
struct remove_cv
{
    using type=typename remove_volatile<typename remove_const<T>::type>::type;
};


template<class T>
struct remove_reference
{
    using type=T;
};

template<class T>
struct remove_reference<T&>
{
    using type=T;
};

template<class T>
struct remove_reference<T&&>
{
    using type=T;
};


template<bool B,class T=void> struct enable_if {};
template<class T> struct enable_if<false,T> {using type=T;};
template<bool B,class T=void> using enable_if_t=typename enable_if<B,T>::type;


template <class T,T v>
struct integral_constant
{
    using value_type=T;
    using type=integral_constant;
    static constexpr T value=v;
    constexpr operator value_type()const noexcept{return value;}
    constexpr value_type operator()()const noexcept{return value;}
};


template <bool B>
using bool_constant=integral_constant<bool,B>;


using true_type=integral_constant<bool,true>;
using false_type=integral_constant<bool,false>;


template<class From,class To>
struct __is_convertible_helper
{
private:
    struct __two_char{char s[2];};
    char __conversion_test(To);
    __two_char __conversion_test(...);
    From make_from();
public:
    using type=bool_constant<sizeof(__conversion_test(make_from()))==sizeof(char)>;
};

template<class From,class To>
struct is_convertible : public __is_convertible_helper<From,To>::type {};

template<class From,class To>
inline constexpr bool is_convertible_v=is_convertible<From,To>::value;


template<class T1,class T2>
struct is_same : public false_type {};

template<class T>
struct is_same<T,T> : public true_type {};


template <class T>
struct is_void : is_same<void,typename remove_cv<T>::type> {};


template <class T>
struct is_null_pointer : public is_same<nullptr_t,typename remove_cv<nullptr_t>::type> {};


template<class T>
struct is_integral : public false_type {};

template<>
struct is_integral<bool> : public true_type {};

template<>
struct is_integral<char> : public true_type {};

template<>
struct is_integral<unsigned char> : public true_type {};

template<>
struct is_integral<char16_t> : public true_type {};

template<>
struct is_integral<char32_t> : public true_type {};

template<>
struct is_integral<wchar_t> : public true_type {};

template<>
struct is_integral<short> : public true_type {};

template<>
struct is_integral<unsigned short> : public true_type {};

template<>
struct is_integral<int> : public true_type {};

template<>
struct is_integral<unsigned int> : public true_type {};

template<>
struct is_integral<long> : public true_type {};

template<>
struct is_integral<unsigned long> : public true_type {};

template<>
struct is_integral<long long> : public true_type {};

template<>
struct is_integral<unsigned long long> : public true_type {};


template<class T>
struct is_floating_point : public false_type {};

template<>
struct is_floating_point<float> : public true_type {};

template<>
struct is_floating_point<double> : public true_type {};

template<>
struct is_floating_point<long double> : public true_type {};


template<class T>
struct is_array : public false_type {};

template<class T>
struct is_array<T[]> : public true_type {};

template<class T,size_t N>
struct is_array<T[N]> : public true_type {};


template<class T>
struct is_pointer_helper : public false_type {};

template<class T>
struct is_pointer_helper<T*> : public true_type {};

template<class T>
struct is_pointer : public is_pointer_helper<typename remove_cv<T>::type> {};


template<class T>
struct is_reference_helper : public false_type {};

template<class T>
struct is_reference_helper<T&> : public true_type {};

template<class T>
struct is_reference : public is_reference_helper<typename remove_cv<T>::type> {};


#ifdef __GNUC__
template<class T>
struct is_union : public integral_constant<bool,__is_union(T)> {};
#else
#endif


namespace detail
{
    template<class T> char test(int (T::*));
    struct large {char d[2];};
    template<class T> large test(...);
}

template<class T>
struct is_class : public integral_constant<bool,sizeof(detail::test<T>(0))==sizeof(char)&&!is_union<T>::value> {};


template<class>
struct is_function : false_type {};

template<class Ret, class... Args>
struct is_function<Ret(Args...)> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......)> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) volatile> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const volatile> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) const> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) volatile> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) const volatile> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) &> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const &> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) volatile &> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const volatile &> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) &> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) const &> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) volatile &> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) const volatile &> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) &&> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const &&> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) volatile &&> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const volatile &&> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) &&> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) const &&> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) volatile &&> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) const volatile &&> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) noexcept> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) noexcept> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const noexcept> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) volatile noexcept> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const volatile noexcept> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) const noexcept> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) volatile noexcept> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) const volatile noexcept> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) & noexcept> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const & noexcept> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) volatile & noexcept> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const volatile & noexcept> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) & noexcept> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) const & noexcept> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) volatile & noexcept> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) const volatile & noexcept> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) && noexcept> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const && noexcept> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) volatile && noexcept> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const volatile && noexcept> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) && noexcept> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) const && noexcept> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) volatile && noexcept> : true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) const volatile && noexcept> : true_type {};


template<class T> struct is_lvalue_reference : false_type {};
template<class T> struct is_lvalue_reference<T&> : true_type {};

template<class T> struct is_rvalue_reference : false_type {};
template<class T> struct is_rvalue_reference<T&&> : true_type {};




#ifdef __GNUC__
template<class T>
struct is_enum : public integral_constant<bool,__is_enum(T)> {};
#else
template<class T>
struct is_enum : public integral_constant<bool, 
    !is_void<T>::value&&
    !is_integral<T>::value&&
    !is_null_pointer<T>::value&&
    !is_floating_point<T>::value&&
    !is_array<T>::value&&
    !is_pointer<T>::value&&
    !is_reference<T>::value&&
    !is_member_pointer<T>::value&&
    !is_union<T>::value&&
    !is_class<T>::value&&
    !is_function<T>::value
> {};
#endif


}

#endif
