1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
|
// 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<typename T>
class function_ref;
template<typename R, typename... Args>
class function_ref<R(Args...)>
{
using InvokeFn = R (*)(Args..., void*);
void* m_obj;
InvokeFn m_invoke;
template<typename T>
static R invoke(Args... args, void* obj)
{
// NOLINTNEXTLINE(*-reinterpret-cast)
return asl::invoke(*reinterpret_cast<T*>(obj), std::forward<Args>(args)...);
}
public:
function_ref() = delete;
ASL_DEFAULT_COPY_MOVE(function_ref);
~function_ref() = default;
template<typename T>
function_ref(T&& t) // NOLINT(*-missing-std-forward, *explicit*)
requires (
!same_as<un_cvref_t<T>, function_ref>
&& invocable<T, Args...>
&& same_as<invoke_result_t<T, Args...>, R>
)
// NOLINTNEXTLINE(*cast*)
: m_obj{const_cast<void*>(reinterpret_cast<const void*>(address_of(t)))}
, m_invoke{invoke<un_ref_t<T>>}
{}
template<typename T>
function_ref& operator=(T&& t) // NOLINT(*-missing-std-forward)
requires (
!same_as<un_cvref_t<T>, function_ref>
&& invocable<T, Args...>
&& same_as<invoke_result_t<T, Args...>, R>
)
{
// NOLINTNEXTLINE(*cast*)
m_obj = const_cast<void*>(reinterpret_cast<const void*>(address_of(t)));
m_invoke = invoke<un_ref_t<T>>;
return *this;
}
constexpr R operator()(this function_ref self, Args... args)
{
return self.m_invoke(std::forward<Args>(args)..., self.m_obj);
}
};
} // namespace asl
|