#ifndef __GBLIBCPP_TYPE_TRAITS__
#define __GBLIBCPP_TYPE_TRAITS__

#include <bits/fwd_functional>
#include <bits/forward>

#include <bits/type_traits/base>
#include <bits/type_traits/is_es>
#include <bits/type_traits/remove_add>

namespace std {

template <typename T>
struct add_const { using type = T const; };
template <typename T>
struct add_volatile { using type = T volatile; };
template <typename T>
struct add_cv { using type = T const volatile; };

template <typename T>
using add_const_t = typename add_const<T>::type;
template <typename T>
using add_volatile_t = typename add_volatile<T>::type;
template <typename T>
using add_cv_t = typename add_cv<T>::type;

template <typename T, typename U>
struct is_same : public false_type {};
template <typename T>
struct is_same<T, T> : public true_type {};

template <typename T, typename U>
inline constexpr bool is_same_v = is_same<T, U>::value;

template <typename T>
struct is_void : public is_same<remove_cv_t<T>, void> {};

template <typename T>
inline constexpr bool is_void_v = is_void<T>::value;

template <typename T>
struct is_pointer : public false_type {};
template <typename T>
struct is_pointer<T*> : public true_type {};
template <typename T>
struct is_pointer<T* const> : public true_type {};
template <typename T>
struct is_pointer<T* volatile> : public true_type {};
template <typename T>
struct is_pointer<T* const volatile> : public true_type {};

template <typename T>
inline constexpr bool is_pointer_v = is_pointer<T>::value;

template <bool B, typename T = void>
struct enable_if {};
template <typename T>
struct enable_if<true, T> { using type = T; };

template <bool B, typename T = void>
using enable_if_t = typename enable_if<B, T>::type;

namespace __helpers {

template <typename From, typename To, typename = void>
struct is_convertible : public false_type {};
template <typename From, typename To>
struct is_convertible<From, To,
    decltype(declval<void(*)(To)>()(declval<From>()))
> : public true_type {};
template <typename Void1, typename Void2>
struct is_convertible<Void1, Void2,
    enable_if_t<is_void_v<Void1> && is_void_v<Void2> >
> : public true_type {};

template <typename From, typename To, typename = void>
struct is_nothrow_convertible : public false_type {};
template <typename From, typename To>
struct is_nothrow_convertible<From, To,
    decltype(declval<void(*)(To)>()(declval<From>()))
> : public true_type {};
template <typename Void1, typename Void2>
struct is_nothrow_convertible<Void1, Void2,
    enable_if_t<is_void_v<Void1> && is_void_v<Void2> >
> : public true_type {};

// TODO: check T is union
template <typename T>
true_type __test_is_class(int T::*);
template <typename T>
false_type __test_is_class(...);

template <typename Base, typename Derived>
auto _try_is_base_of(...) -> true_type;

template <typename Base, typename Derived>
auto _try_is_base_of() ->
    decltype(void());

template <typename Base>
true_type __conv_base_pointer(const volatile Base*);
template <typename>
false_type __conv_base_pointer(const volatile void*);

template <typename Base, typename Derived>
decltype(__conv_base_pointer<Base>(declval<Derived*>()))
try_is_base_of(int);

template <typename, typename>
true_type try_is_base_of(...);

} // namespace __helpers

template <typename From, typename To>
struct is_convertible : public __helpers::is_convertible<From, To> {};
template <typename From, typename To>
struct is_nothrow_convertible : public __helpers::is_nothrow_convertible<From, To> {};

template <typename From, typename To>
inline constexpr bool is_convertible_v = is_convertible<From, To>::value;
template <typename From, typename To>
inline constexpr bool is_nothrow_convertible_v = is_nothrow_convertible<From, To>::value;

template <typename T>
struct is_class : public decltype(__helpers::__test_is_class<T>(nullptr)) {};

template <typename T>
inline constexpr bool is_class_v = is_class<T>::value;

template <typename Base, typename Derived>
struct is_base_of : public bool_constant<
    is_class_v<Base> && is_class_v<Derived>
    && decltype(__helpers::try_is_base_of<Base, Derived>(0))::value
> {};

template <typename Base, typename Derived>
inline constexpr bool is_base_of_v = is_base_of<Base, Derived>::value;

namespace __helpers {

template <typename>
struct is_reference_wrapper : public false_type {};
template <typename T>
struct is_reference_wrapper<reference_wrapper<T>> : public true_type {};

template <typename FuncType>
struct __invoke_impl {
    template <typename Func, typename... Args>
    static auto __invoke(Func&& func, Args&&... args)
        noexcept(noexcept(forward<Func>(func)(forward<Args>(args)...)))
        -> decltype(forward<Func>(func)(forward<Args>(args)...)) {
        return forward<Func>(func)(forward<Args>(args)...);
    }
};

template <typename T, typename Ret>
struct __invoke_impl<Ret T::*> {
    template <typename _T1, typename T1 = decay_t<_T1>, typename = enable_if_t<
        is_same_v<T, T1> || is_base_of_v<T, T1>
        >>
    static auto get(_T1&& val) -> _T1&& {
        return forward<_T1>(val);
    }

    template <typename _T1, typename T1 = decay_t<_T1>, typename = enable_if_t<
        is_reference_wrapper<T1>::value
        >>
    static auto get(_T1&& val) -> decltype(val.get()) {
        return val.get();
    }

    template <typename _T1, typename T1 = decay_t<_T1>, typename = enable_if_t<
        !is_same_v<T, T1> && !is_base_of_v<T, T1>
        && !is_reference_wrapper<T1>::value
        >>
    static auto get(_T1&& val) -> decltype(*forward<_T1>(val)) {
        return *forward<_T1>(val);
    }

    template <typename T1, typename... Args>
    static auto __invoke(Ret T::*pmf, T1&& t1, Args&&... args)
        noexcept(noexcept((forward<T1>(t1).*pmf)(forward<Args>(args)...)))
        -> decltype((get(forward<T1>(t1)).*pmf)(forward<Args>(args)...)) {
        return (get(forward<T1>(t1)).*pmf)(forward<Args>(args)...);
    }

    template <typename T1>
    static auto __invoke(Ret T::*pdm, T1&& t1) noexcept
        -> decltype(get(forward<T1>(t1)).*pdm) {
        return get(forward<T1>(t1)).*pdm;
    }
};

template <typename Func, typename... Args, typename FuncBase = decay_t<Func>>
auto INVOKE(Func&& func, Args&&... args)
    noexcept(noexcept(__invoke_impl<FuncBase>::__invoke(
        forward<Func>(func), forward<Args>(args)...)))
    -> decltype(__invoke_impl<FuncBase>::__invoke(
        forward<Func>(func), forward<Args>(args)...))
{
    return __invoke_impl<FuncBase>::__invoke(
    forward<Func>(func), forward<Args>(args)...);
}

template <typename Func, typename = void, typename... Args>
struct __is_invocable : public false_type {};

template <typename Func, typename... Args>
struct __is_invocable<Func, void_t<
    decltype(INVOKE(declval<Func>(), declval<Args>()...))>,
    Args...> : public true_type {};

template <typename Func, typename = void, typename... Args>
struct __invoke_result {};

template <typename Func, typename... Args>
struct __invoke_result<Func, enable_if_t<
    __is_invocable<Func, void, Args...>::value
>, Args...> {
    using type = decltype(INVOKE(declval<Func>(), declval<Args>()...));
};

template <typename R, typename Func, typename... Args>
enable_if_t<
    is_convertible_v<typename __invoke_result<Func, void, Args...>::type, R>, R>
INVOKE_R(Func&& func, Args&&... args)
    noexcept(
        noexcept(INVOKE(forward<Func>(func), forward<Args>(args)...))
        && noexcept(is_nothrow_convertible_v<
            typename __invoke_result<Func, void, Args...>::type, R>)
    )
{
    return INVOKE(forward<Func>(func), forward<Args>(args)...);
}

template <typename R, typename Func, typename = void, typename... Args>
struct __is_invocable_r : public false_type {};

template <typename R, typename Func, typename... Args>
struct __is_invocable_r<R, Func, void_t<
    decltype(INVOKE_R<R>(declval<Func>(), declval<Args>()...))>,
    Args...> : public true_type {};

} // namespace __helpers

template <typename Func, typename... Args>
struct is_invocable : __helpers::__is_invocable<Func, void, Args...> {};
template <typename R, typename Func, typename... Args>
struct is_invocable_r : __helpers::__is_invocable_r<R, Func, void, Args...> {};

template <typename Func, typename... Args>
struct is_nothrow_invocable : bool_constant<
    is_invocable<Func, Args...>::value
    && noexcept(__helpers::INVOKE(declval<Func>(), declval<Args>()...))
> {};
template <typename R, typename Func, typename... Args>
struct is_nothrow_invocable_r : bool_constant<
    is_invocable_r<R, Func, Args...>::value
    && noexcept(__helpers::INVOKE_R<R>(declval<Func>(), declval<Args>()...))
> {};

template <typename Func, typename... Args>
inline constexpr bool is_invocable_v = is_invocable<Func, Args...>::value;
template <typename R, typename Func, typename... Args>
inline constexpr bool is_invocable_r_v = is_invocable_r<R, Func, Args...>::value;
template <typename Func, typename... Args>
inline constexpr bool is_nothrow_invocable_v = is_nothrow_invocable<Func, Args...>::value;
template <typename R, typename Func, typename... Args>
inline constexpr bool is_nothrow_invocable_r_v = is_nothrow_invocable_r<R, Func, Args...>::value;

template <typename Func, typename... Args>
struct invoke_result : __helpers::__invoke_result<Func, void, Args...> {};

template <class Func, class... Args>
using invoke_result_t = typename invoke_result<Func, Args...>::type;

template <typename T, typename U, typename = void>
struct is_assignable : public false_type {};

template <typename T, typename U>
struct is_assignable<T, U, void_t<
    decltype(std::declval<T>() = std::declval<U>())>> : public true_type {};

template <typename T, typename U>
inline constexpr bool is_assignable_v = is_assignable<T, U>::value;

#if defined(__GNUC__) or defined(__clang__)

template <typename T, typename... Args>
struct is_constructible
    : public bool_constant<__is_constructible(T, Args...)> {};

#else

namespace __helpers {

template <typename T, typename = void, typename... Args>
struct is_constructible_impl : public false_type {};

template <typename T, typename... Args>
struct is_constructible_impl<T, void_t<
    decltype(
        T { declval<Args>()... }
    )>, Args...> : public true_type {};

} // namespace __helpers

template <typename T, typename... Args>
struct is_constructible
    : public __helpers::is_constructible_impl<T, void, Args...> {};

#endif

template <typename T>
struct is_default_constructible : public is_constructible<T> {};

template <typename T>
struct is_copy_constructible
    : public is_constructible<T, add_lvalue_reference_t<add_const_t<T>>> {};

template <typename T>
struct is_move_constructible
    : public is_constructible<T, add_rvalue_reference_t<T>> {};

template <typename T, typename... Args>
inline constexpr bool is_constructible_v = is_constructible<T, Args...>::value;
template <typename T>
inline constexpr bool is_default_constructible_v = is_default_constructible<T>::value;
template <typename T>
inline constexpr bool is_copy_constructible_v = is_copy_constructible<T>::value;
template <typename T>
inline constexpr bool is_move_constructible_v = is_move_constructible<T>::value;

#define __CPP_GREATBRIDF
#ifdef __CPP_GREATBRIDF

template <typename U, template <typename...> class T, typename...>
struct is_template_instance : public false_type {
};
template <template <typename...> class T, typename... Ts>
struct is_template_instance<T<Ts...>, T, Ts...> : public true_type {
};

template <typename U, template <typename...> class T, typename... Ts>
inline constexpr bool is_template_instance_v = is_template_instance<U, T, Ts...>::value;

template <typename T>
using template_false_type = __helpers::template_false_type<T>;
template <typename T>
using template_true_type = __helpers::template_true_type<T>;

#endif

} // namespace std

#endif
