// 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 constexpr auto invoke(F&& f, Args&&... args) -> decltype(std::forward(f)(std::forward(args)...)) requires (!is_member_ptr>) && requires { f(std::forward(args)...); } { return std::forward(f)(std::forward(args)...); } template constexpr auto&& invoke(auto C::* f, same_or_derived_from auto&& arg) { return std::forward(arg).*f; } template constexpr auto&& invoke(auto C::* f, auto&& arg) requires ( !same_or_derived_from && requires { (*arg).*f; } ) { return (*std::forward(arg)).*f; } template constexpr auto invoke(is_func auto C::* f, same_or_derived_from auto&& self, Args&&... args) -> decltype((std::forward(self).*f)(std::forward(args)...)) requires requires { (self.*f)(std::forward(args)...); } { return (std::forward(self).*f)(std::forward(args)...); } template constexpr auto invoke(is_func auto C::* f, auto&& self, Args&&... args) -> decltype(((*std::forward(self)).*f)(std::forward(args)...)) requires ( !same_or_derived_from && requires { ((*self).*f)(std::forward(args)...); } ) { return ((*std::forward(self)).*f)(std::forward(args)...); } template constexpr R invoke_r(F&& f, Args&&... args) { if constexpr (is_void) { static_cast(invoke(std::forward(f), std::forward(args)...)); } else { return invoke(std::forward(f), std::forward(args)...); } } template struct _invoke_result_helper; template struct _invoke_result_helper { using type = decltype(invoke(declval(), declval()...)); }; template using invoke_result_t = _invoke_result_helper::type; template concept invocable = requires (F&& f, Args&&... args) { invoke(std::forward(f), std::forward(args)...); }; template concept invocable_r = invocable && (is_void || convertible_to, R>); } // namespace asl