// Copyright 2025 Steven Le Rouzic // // SPDX-License-Identifier: BSD-3-Clause #pragma once #include "asl/base/meta.hpp" #include "asl/base/utility.hpp" namespace asl { template<typename... Args, typename C> constexpr auto invoke(is_func auto C::* f, auto&& self, Args&&... args) -> decltype((self.*f)(std::forward<Args>(args)...)) requires requires { (self.*f)(std::forward<Args>(args)...); } { return (std::forward<decltype(self)>(self).*f)(std::forward<Args>(args)...); } template<typename... Args, typename C> constexpr auto invoke(is_func auto C::* f, auto* self, Args&&... args) -> decltype((self->*f)(std::forward<Args>(args)...)) requires requires { (self->*f)(std::forward<Args>(args)...); } { return (self->*f)(std::forward<Args>(args)...); } template<typename... Args, typename C> constexpr auto invoke(is_object auto C::* m, auto&& self, Args&&...) -> decltype(self.*m) requires ( sizeof...(Args) == 0 && requires { self.*m; } ) { return std::forward<decltype(self)>(self).*m; } template<typename... Args, typename C> constexpr auto invoke(is_object auto C::* m, auto* self, Args&&...) -> decltype(self->*m) requires ( sizeof...(Args) == 0 && requires { self->*m; } ) { return self->*m; } template<typename... Args> constexpr auto invoke(auto&& f, Args&&... args) -> decltype(f(std::forward<Args>(args)...)) requires requires { f(std::forward<Args>(args)...); } { return std::forward<decltype(f)>(f)(std::forward<Args>(args)...); } template<typename Void, typename F, typename... Args> struct _invoke_result_helper; template<typename R, typename... Args> struct _invoke_result_helper<void, R, Args...> { using type = decltype(invoke(declval<R>(), declval<Args>()...)); }; template<typename F, typename... Args> using invoke_result_t = _invoke_result_helper<void, F, Args...>::type; template<typename F, typename... Args> concept invocable = requires (F&& f, Args&&... args) { invoke(std::forward<F>(f), std::forward<Args>(args)...); }; } // namespace asl