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