#ifndef __GBLIBCPP_FUNCTIONAL__ #define __GBLIBCPP_FUNCTIONAL__ #include #include #include #include #include #include namespace std { template constexpr auto invoke(Func&& func, Args&&... args) noexcept(std::is_nothrow_invocable_v) -> std::enable_if_t, std::invoke_result_t> { return __helpers::INVOKE(std::forward(func), std::forward(args)...); } template constexpr auto invoke_r(Func&& func, Args&&... args) noexcept(std::is_nothrow_invocable_r_v) -> std::enable_if_t, R> { return __helpers::INVOKE_R(std::forward(func), std::forward(args)...); } namespace __helpers { template constexpr void __reference_wrapper_check(T&) noexcept {} template void __reference_wrapper_check(T&&) = delete; } // namespace __helpers template class reference_wrapper { private: T* _ptr; template (std::declval()))> struct __check_reference_valid : public bool_constant>> {}; public: using type = T; constexpr T& get(void) const noexcept { return *_ptr; } constexpr operator T&(void) const noexcept { return *_ptr; } template ::value, bool> = true> constexpr reference_wrapper(U&& ref) noexcept(noexcept(__helpers::__reference_wrapper_check(std::declval()))) : _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 constexpr invoke_result_t operator()(Args&&... args) const noexcept(is_nothrow_invocable_v) { return std::invoke(get(), std::forward(args)...); } }; template reference_wrapper(T&) -> reference_wrapper; namespace __inner { template 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 class _function : public _function_base { private: using __enable = std::enable_if_t< std::is_same_v>()(std::declval()...))> >; 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)...); } constexpr void copy_to(_function_base* dst) override { new (reinterpret_cast<_function*>(dst)) _function(*this); } constexpr void move_to(_function_base* dst) override { new (reinterpret_cast<_function*>(dst)) _function(std::move(*this)); } constexpr explicit operator bool(void) const override { return true; } }; template class _function : public _function_base { 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* dst) override { new (reinterpret_cast<_function*>(dst)) _function(*this); } constexpr void move_to(_function_base* dst) override { new (reinterpret_cast<_function*>(dst)) _function(std::move(*this)); } constexpr explicit operator bool(void) const override { return false; } }; } // namespace __inner template class function { public: using result_type = Ret; private: static constexpr std::size_t STACK_ALLOCATED_SIZE = 12; char _data[STACK_ALLOCATED_SIZE]; using fb_t = __inner::_function_base; 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(); } 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 >()(std::declval()...)) > && (sizeof(std::decay_t) <= STACK_ALLOCATED_SIZE - sizeof(void*)) && !std::is_same_v, function> , bool> = true > constexpr function(FuncLike&& func) { new (_f()) __inner::_function, Ret, Args...>(std::forward(func)); } constexpr ~function() { _clear(); } constexpr Ret operator()(Args... args) const { return (*_f())(std::forward(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(); return *this; } template >()(std::declval()...)) > && (sizeof(std::decay_t) <= sizeof(_data)) && !std::is_same_v, function> , bool> = true > function& operator=(FuncLike&& func) { function{std::forward(func)}.swap(*this); return *this; } template function& operator=(std::reference_wrapper func) noexcept { function{func}.swap(*this); return *this; } }; template bool operator==(const std::function& func, std::nullptr_t) noexcept { return !func; } template void swap(std::function& lhs, std::function& rhs) noexcept { return lhs.swap(rhs); } template constexpr std::reference_wrapper ref(T& t) noexcept { return std::reference_wrapper((t)); } template constexpr std::reference_wrapper ref(std::reference_wrapper t) noexcept { return t; } template constexpr std::reference_wrapper cref(const T& t) noexcept { return std::reference_wrapper((t)); } template constexpr std::reference_wrapper cref(std::reference_wrapper t) noexcept { return t; } // Comparators template struct less { constexpr bool operator()(const T& lhs, const T& rhs) const { return lhs < rhs; } }; template <> struct less { template constexpr auto operator()(T&& lhs, U&& rhs) const -> decltype(std::forward(lhs) < std::forward(rhs)) { return std::forward(lhs) < std::forward(rhs); } }; template struct greater { constexpr bool operator()(const T& lhs, const T& rhs) const { return lhs > rhs; } }; template <> struct greater { template constexpr auto operator()(T&& lhs, U&& rhs) const -> decltype(std::forward(lhs) > std::forward(rhs)) { return std::forward(lhs) > std::forward(rhs); } }; } // namespace std #endif