// Copyright 2025 Steven Le Rouzic // // SPDX-License-Identifier: BSD-3-Clause #pragma once #include "asl/base/utility.hpp" #include "asl/base/meta.hpp" #include "asl/base/functional.hpp" #include "asl/memory/memory.hpp" namespace asl { template class function_ref; template class function_ref { using InvokeFn = R (*)(Args..., void*); void* m_obj; InvokeFn m_invoke; template static R invoke(Args... args, void* obj) { // NOLINTNEXTLINE(*-reinterpret-cast) return asl::invoke(*reinterpret_cast(obj), std::forward(args)...); } public: function_ref() = delete; ASL_DEFAULT_COPY_MOVE(function_ref); ~function_ref() = default; template function_ref(T&& t) // NOLINT(*-missing-std-forward, *explicit*) requires ( !same_as, function_ref> && invocable && same_as, R> ) // NOLINTNEXTLINE(*cast*) : m_obj{const_cast(reinterpret_cast(address_of(t)))} , m_invoke{invoke>} {} template function_ref& operator=(T&& t) // NOLINT(*-missing-std-forward) requires ( !same_as, function_ref> && invocable && same_as, R> ) { // NOLINTNEXTLINE(*cast*) m_obj = const_cast(reinterpret_cast(address_of(t))); m_invoke = invoke>; return *this; } constexpr R operator()(this function_ref self, Args... args) { return self.m_invoke(std::forward(args)..., self.m_obj); } }; } // namespace asl