#ifndef __GBLIBCPP_FUNCTIONAL__
#define __GBLIBCPP_FUNCTIONAL__

#include <bits/fwd_functional>

#include <cstddef>
#include <memory>
#include <new>
#include <utility>
#include <type_traits>

namespace std {

template <typename Func, typename... Args>
constexpr auto invoke(Func&& func, Args&&... args)
    noexcept(std::is_nothrow_invocable_v<Func, Args...>)
    -> std::enable_if_t<std::is_invocable_v<Func, Args...>,
        std::invoke_result_t<Func, Args...>>
{
    return __helpers::INVOKE(std::forward<Func>(func), std::forward<Args>(args)...);
}

template <typename R, typename Func, typename... Args>
constexpr auto invoke_r(Func&& func, Args&&... args)
    noexcept(std::is_nothrow_invocable_r_v<R, Func, Args...>)
    -> std::enable_if_t<std::is_invocable_r_v<R, Func, Args...>, R>
{
    return __helpers::INVOKE_R<R>(std::forward<Func>(func), std::forward<Args>(args)...);
}

namespace __helpers {
template <typename T> constexpr void __reference_wrapper_check(T&) noexcept {}
template <typename T> void __reference_wrapper_check(T&&) = delete;
} // namespace __helpers

template <typename T>
class reference_wrapper {
private:
    T* _ptr;

    template <typename Ref, typename =
        decltype(__helpers::__reference_wrapper_check<T>(std::declval<Ref>()))>
    struct __check_reference_valid
        : public bool_constant<!std::is_same_v<reference_wrapper, std::decay_t<Ref>>> {};

public:
    using type = T;

    constexpr T& get(void) const noexcept { return *_ptr; }
    constexpr operator T&(void) const noexcept { return *_ptr; }

    template <typename U, std::enable_if_t<__check_reference_valid<U>::value, bool> = true>
    constexpr reference_wrapper(U&& ref)
        noexcept(noexcept(__helpers::__reference_wrapper_check<T>(std::declval<U>())))
        : _ptr(std::addressof(ref)) {}

    constexpr reference_wrapper(const reference_wrapper& val) noexcept
    {
        _ptr = val._ptr;
    }
    constexpr reference_wrapper& operator=(const reference_wrapper& val) noexcept = default;

    // TODO: std::invoke_result_t
    template <typename... Args>
    constexpr invoke_result_t<type&, Args...>
    operator()(Args&&... args) const noexcept(is_nothrow_invocable_v<type&, Args...>)
    {
        return std::invoke(get(), std::forward<Args>(args)...);
    }
};
template <typename T>
reference_wrapper(T&) -> reference_wrapper<T>;

namespace __inner {

    template <typename Ret, typename... Args>
    class _function_base {
    public:
        virtual constexpr ~_function_base() = default;
        virtual constexpr Ret operator()(Args... args) const = 0;
        virtual constexpr void copy_to(_function_base* func) = 0;
        virtual constexpr void move_to(_function_base* func) = 0;
        virtual explicit constexpr operator bool(void) const = 0;
    };

    template <typename FuncLike, typename Ret, typename... Args>
    class _function : public _function_base<Ret, Args...> {
    private:
        using __enable = std::enable_if_t<
            std::is_invocable_r_v<Ret, std::decay_t<FuncLike>, Args...>
        >;
        FuncLike func;

    public:
        constexpr _function(const FuncLike& _func) : func(_func) {}
        constexpr _function(FuncLike&& _func) : func(std::move(_func)) {}

        constexpr Ret operator()(Args... args) const override
        {
            return std::invoke(func, std::forward<Args>(args)...);
        }

        constexpr void copy_to(_function_base<Ret, Args...>* dst) override
        {
            new (reinterpret_cast<_function*>(dst)) _function(*this);
        }

        constexpr void move_to(_function_base<Ret, Args...>* dst) override
        {
            new (reinterpret_cast<_function*>(dst)) _function(std::move(*this));
        }

        constexpr explicit operator bool(void) const override
        {
            return true;
        }
    };

    template <typename Ret, typename... Args>
    class _function<nullptr_t, Ret, Args...> : public _function_base<Ret, Args...> {
    public:
        [[noreturn]] Ret operator()(Args...) const override
        {
            // TODO: exception
            *((int*)(100^100)) = 1; // triggers access to null pointer
            for (;;);
        }
        constexpr void copy_to(_function_base<Ret, Args...>* dst) override
        {
            new (reinterpret_cast<_function*>(dst)) _function(*this);
        }
        constexpr void move_to(_function_base<Ret, Args...>* dst) override
        {
            new (reinterpret_cast<_function*>(dst)) _function(std::move(*this));
        }
        constexpr explicit operator bool(void) const override
        {
            return false;
        }
    };

} // namespace __inner

template <typename Ret, typename... Args>
class function<Ret(Args...)> {
public:
    using result_type = Ret;

private:
    static constexpr std::size_t STACK_ALLOCATED_SIZE = 24;

    char _data[STACK_ALLOCATED_SIZE];
    using fb_t = __inner::_function_base<Ret, Args...>;
    constexpr fb_t* _f(void) const
    {
        return (fb_t*)_data;
    }

    constexpr void _clear(void)
    {
        _f()->~_function_base();
    }

public:
    constexpr function() noexcept
    {
        new (_f()) __inner::_function<nullptr_t, Ret, Args...>();
    }
    constexpr function(nullptr_t) noexcept : function() {}
    constexpr function(const function& func)
    {
        func._f()->copy_to(_f());
    }
    constexpr function(function&& func) noexcept
    {
        func._f()->move_to(_f());
    }

    template <typename FuncLike, std::enable_if_t
        <
            // TODO: check its behavior for nullptr
            std::is_invocable_r_v<Ret, std::decay_t<FuncLike>, Args...>
            && (sizeof(std::decay_t<FuncLike>) <= STACK_ALLOCATED_SIZE - sizeof(void*))
            && !std::is_same_v<std::decay_t<FuncLike>, function>
        , bool> = true
    >
    constexpr function(FuncLike&& func)
    {
        new (_f()) __inner::_function<std::decay_t<FuncLike>, Ret, Args...>(std::forward<FuncLike>(func));
    }

    constexpr ~function()
    {
        _clear();
    }

    constexpr Ret operator()(Args... args) const
    {
        return (*_f())(std::forward<Args>(args)...);
    }

    explicit operator bool(void) const noexcept
    {
        return !!*_f();
    }

    function& operator=(function&& rhs)
    {
        _clear();
        rhs._f()->move_to(_f());
        return *this;
    }

    void swap(function& other) noexcept
    {
        function tmp(std::move(other));
        other = std::move(*this);
        *this = std::move(tmp);
    }

    function& operator=(const function& rhs)
    {
        _clear();
        rhs._f()->copy_to(_f());
        return *this;
    }

    function& operator=(nullptr_t) noexcept
    {
        _clear();
        new (_f()) __inner::_function<nullptr_t, Ret, Args...>();
        return *this;
    }

    template <typename FuncLike, std::enable_if_t
        <
            std::is_same_v<
                Ret,
                decltype(std::declval<std::decay_t<FuncLike>>()(std::declval<Args>()...))
            >
            && (sizeof(std::decay_t<FuncLike>) <= sizeof(_data))
            && !std::is_same_v<std::decay_t<FuncLike>, function>
        , bool> = true
    >
    function& operator=(FuncLike&& func)
    {
        function{std::forward<FuncLike>(func)}.swap(*this);
        return *this;
    }

    template <typename FuncLike>
    function& operator=(std::reference_wrapper<FuncLike> func) noexcept
    {
        function{func}.swap(*this);
        return *this;
    }
};

template <typename Ret, typename... Args>
bool operator==(const std::function<Ret(Args...)>& func, std::nullptr_t) noexcept
{
    return !func;
}

template <typename Ret, typename... Args>
void swap(std::function<Ret(Args...)>& lhs, std::function<Ret(Args...)>& rhs) noexcept
{
    return lhs.swap(rhs);
}

template <typename T>
constexpr std::reference_wrapper<T> ref(T& t) noexcept
{
    return std::reference_wrapper<T>((t));
}

template <typename T>
constexpr std::reference_wrapper<T>
    ref(std::reference_wrapper<T> t) noexcept
{
    return t;
}

template <typename T>
constexpr std::reference_wrapper<const T> cref(const T& t) noexcept
{
    return std::reference_wrapper<const T>((t));
}

template <typename T>
constexpr std::reference_wrapper<const T>
    cref(std::reference_wrapper<T> t) noexcept
{
    return t;
}

// Comparators

template <typename T = void>
struct less {
    constexpr bool operator()(const T& lhs, const T& rhs) const
    { return lhs < rhs; }
};

template <>
struct less<void> {
    template <typename T, typename U>
    constexpr auto operator()(T&& lhs, U&& rhs) const
        -> decltype(std::forward<T>(lhs) < std::forward<U>(rhs))
    { return std::forward<T>(lhs) < std::forward<U>(rhs); }
};

template <typename T = void>
struct greater {
    constexpr bool operator()(const T& lhs, const T& rhs) const
    { return lhs > rhs; }
};

template <>
struct greater<void> {
    template <typename T, typename U>
    constexpr auto operator()(T&& lhs, U&& rhs) const
        -> decltype(std::forward<T>(lhs) > std::forward<U>(rhs))
    { return std::forward<T>(lhs) > std::forward<U>(rhs); }
};

} // namespace std

#endif
