Iros
 
Loading...
Searching...
No Matches
function_ref.h
Go to the documentation of this file.
1#pragma once
2
5#include "di/meta/algorithm.h"
6#include "di/meta/constexpr.h"
7#include "di/meta/language.h"
8#include "di/meta/util.h"
9#include "di/types/prelude.h"
10#include "di/util/addressof.h"
11
12namespace di::function {
13namespace function_ref_ns {
14 template<typename F, typename T>
16
17 template<typename T, typename R, typename U, typename... Args>
18 struct SignatureAfterBindFrontHelper<R (*)(U, Args...), T> : meta::TypeConstant<R(Args...)> {};
19
20 template<typename T, typename M, typename G>
21 requires(concepts::Object<M>)
22 struct SignatureAfterBindFrontHelper<M G::*, T> : meta::TypeConstant<meta::InvokeResult<M G::*, T>> {};
23
24 template<typename T, typename M, typename G>
26 struct SignatureAfterBindFrontHelper<M G::*, T> : meta::TypeConstant<meta::RemoveFunctionQualifiers<M>> {};
27
28 template<typename F, typename T>
30
31 template<typename Function>
33
34 template<typename R, typename... Args>
35 struct SignatureInfo<R(Args...)> {
36 using Type = R(Args...);
37
38 template<typename... Fs>
39 constexpr static bool is_invocable = concepts::InvocableR<R, Fs..., Args...>;
40
41 constexpr static bool is_noexcept = false;
42
43 template<typename T>
44 using Qualified = T;
45 };
46
47 template<typename R, typename... Args>
48 struct SignatureInfo<R(Args...) const> {
49 using Type = R(Args...);
50
51 template<typename... Fs>
52 constexpr static bool is_invocable = concepts::InvocableR<R, Fs..., Args...>;
53
54 constexpr static bool is_noexcept = false;
55
56 template<typename T>
57 using Qualified = T const;
58 };
59
60 template<typename R, typename... Args>
61 struct SignatureInfo<R(Args...) noexcept> {
62 using Type = R(Args...);
63
64 template<typename... Fs>
65 constexpr static bool is_invocable = concepts::InvocableR<R, Fs..., Args...>;
66
67 constexpr static bool is_noexcept = true;
68
69 template<typename T>
70 using Qualified = T;
71 };
72
73 template<typename R, typename... Args>
74 struct SignatureInfo<R(Args...) const noexcept> {
75 using Type = R(Args...);
76
77 template<typename... Fs>
78 constexpr static bool is_invocable = concepts::InvocableR<R, Fs..., Args...>;
79
80 constexpr static bool is_noexcept = true;
81
82 template<typename T>
83 using Qualified = T const;
84 };
85
87 void* pointer { nullptr };
88 void const* const_pointer;
90
91 constexpr ErasedStorage() = default;
92
93 template<concepts::Object T>
94 constexpr explicit ErasedStorage(T* pointer_) : pointer(pointer_) {}
95
96 template<concepts::Object T>
97 constexpr explicit ErasedStorage(T const* const_pointer_) : const_pointer(const_pointer_) {}
98
99 template<concepts::LanguageFunction T>
100 explicit ErasedStorage(T* function_pointer_)
101 : function_pointer(reinterpret_cast<void (*)()>(function_pointer_)) {}
102 };
103
104 template<typename T>
105 constexpr auto down_cast(ErasedStorage storage) {
106 if constexpr (concepts::Const<T>) {
107 return static_cast<T*>(storage.const_pointer);
108 } else if constexpr (concepts::Object<T>) {
109 return static_cast<T*>(storage.pointer);
110 } else {
111 return reinterpret_cast<T*>(storage.function_pointer);
112 }
113 }
114
115 template<typename Sig, typename = meta::Type<SignatureInfo<Sig>>>
117
118 template<typename Sig, typename R, typename... Args>
119 class FunctionRef<Sig, R(Args...)> {
120 private:
121 using Info = SignatureInfo<Sig>;
122
123 template<typename... Fs>
124 constexpr static bool is_invocable = Info::template is_invocable<Fs...>;
125
126 constexpr static bool is_noexcept = Info::is_noexcept;
127
128 template<typename T>
129 using CVQualified = Info::template Qualified<T>;
130
131 // For function ref, every function is lvalue qualified.
132 template<typename T>
133 using Qualified = CVQualified<T>&;
134
135 using ErasedFunctionPointer = R (*)(ErasedStorage, Args&&...) noexcept(is_noexcept);
136
137 public:
138 template<concepts::LanguageFunction F>
139 requires(is_invocable<F>)
140 constexpr FunctionRef(F* function)
141 : m_storage(function), m_impl([](ErasedStorage storage, Args&&... args) noexcept(is_noexcept) -> R {
142 return function::invoke_r<R>(down_cast<F>(storage), util::forward<Args>(args)...);
143 }) {
144 DI_ASSERT(function != nullptr);
145 }
146
147 template<typename F, typename T = meta::RemoveReference<F>>
149 is_invocable<Qualified<F>>)
150 // NOLINTNEXTLINE(bugprone-forwarding-reference-overload)
151 constexpr FunctionRef(F&& function)
152 : m_storage(util::addressof(function))
153 , m_impl([](ErasedStorage storage, Args&&... args) noexcept(is_noexcept) -> R {
154 // Ensure we are invoking the object with the correct const and lvalue qualifications.
155 Qualified<T> object_reference = *down_cast<T>(storage);
156 return function::invoke_r<R>(object_reference, util::forward<Args>(args)...);
157 }) {}
158
159 template<auto f, typename F = decltype(f)>
160 requires(is_invocable<F>)
162 : m_impl([](ErasedStorage, Args&&... args) noexcept(is_noexcept) -> R {
163 return function::invoke_r<R>(f, util::forward<Args>(args)...);
164 }) {
166#ifndef DI_SANITIZER
167 static_assert(f != nullptr, "FunctionRef Constexpr<> constructors cannot be passed a nullptr.");
168#endif
169 }
170 }
171
172 template<auto f, typename U, typename F = decltype(f), typename T = meta::RemoveReference<U>>
173 requires(!concepts::RValueReference<U &&> && is_invocable<F, Qualified<T>>)
174 constexpr FunctionRef(Constexpr<f>, U&& object)
175 : m_storage(util::addressof(object))
176 , m_impl([](ErasedStorage storage, Args&&... args) noexcept(is_noexcept) -> R {
177 // Ensure we are invoking the object with the correct const and lvalue qualifications.
178 Qualified<T> object_reference = *down_cast<T>(storage);
179 return function::invoke_r<R>(f, object_reference, util::forward<Args>(args)...);
180 }) {
182#ifndef DI_SANITIZER
183 static_assert(f != nullptr, "FunctionRef Constexpr<> constructors cannot be passed a nullptr.");
184#endif
185 }
186 }
187
188 template<auto f, typename T, typename F = decltype(f)>
189 requires(is_invocable<F, CVQualified<T>*>)
190 constexpr FunctionRef(Constexpr<f>, CVQualified<T>* object)
191 : m_storage(object), m_impl([](ErasedStorage storage, Args&&... args) noexcept(is_noexcept) -> R {
192 return function::invoke_r<R>(f, down_cast<CVQualified<T>>(storage), util::forward<Args>(args)...);
193 }) {
195#ifndef DI_SANITIZER
196 static_assert(f != nullptr, "FunctionRef Constexpr<> constructors cannot be passed a nullptr.");
197#endif
198 }
199 DI_ASSERT(object != nullptr);
200 }
201
202 template<typename T>
203 requires(!concepts::SameAs<T, FunctionRef> && !concepts::Pointer<T> && is_invocable<Qualified<T>>)
204 auto operator=(T) -> FunctionRef& = delete;
205
206 constexpr auto operator()(Args... args) const noexcept(is_noexcept) -> R {
207 return m_impl(m_storage, util::forward<Args>(args)...);
208 }
209
210 private:
211 ErasedStorage m_storage;
212 ErasedFunctionPointer m_impl { nullptr };
213 };
214
215 template<concepts::LanguageFunction F>
217
218 template<auto f, typename F = meta::RemovePointer<decltype(f)>>
221
222 template<auto f, typename T, typename F = decltype(f)>
224}
225
227}
228
229namespace di {
231}
#define DI_ASSERT(...)
Definition assert_bool.h:7
Definition function_ref.h:116
constexpr FunctionRef(Constexpr< f >, U &&object)
Definition function_ref.h:174
constexpr FunctionRef(F *function)
Definition function_ref.h:140
constexpr FunctionRef(Constexpr< f >)
Definition function_ref.h:161
constexpr FunctionRef(Constexpr< f >, CVQualified< T > *object)
Definition function_ref.h:190
constexpr auto operator()(Args... args) const noexcept(is_noexcept) -> R
Definition function_ref.h:206
constexpr FunctionRef(F &&function)
Definition function_ref.h:151
Definition language.h:18
Definition invoke.h:73
Definition language.h:64
Definition language.h:171
Definition language.h:370
Definition language.h:61
Definition language.h:44
Definition core.h:114
Definition function_ref.h:13
meta::Type< SignatureAfterBindFrontHelper< F, T > > SignatureAfterBindFront
Definition function_ref.h:29
constexpr auto down_cast(ErasedStorage storage)
Definition function_ref.h:105
Definition as_bool.h:8
constexpr auto invoke_r
Definition invoke.h:103
Definition merge_interfaces.h:6
T::Type Type
Definition core.h:26
decltype(function::detail::invoke_impl(util::declval< Ts >()...)) InvokeResult
Definition invoke.h:64
Definition vocab.h:96
Definition zstring_parser.h:9
R(Args...) Type
Definition function_ref.h:36
static constexpr bool is_invocable
Definition function_ref.h:65
static constexpr bool is_noexcept
Definition function_ref.h:80
static constexpr bool is_invocable
Definition function_ref.h:39
static constexpr bool is_invocable
Definition function_ref.h:52
static constexpr bool is_noexcept
Definition function_ref.h:41
static constexpr bool is_noexcept
Definition function_ref.h:67
static constexpr bool is_noexcept
Definition function_ref.h:54
static constexpr bool is_invocable
Definition function_ref.h:78
A wrapper for a constexpr value.
Definition core.h:77
Definition core.h:18
void const * const_pointer
Definition function_ref.h:88
void * pointer
Definition function_ref.h:87
constexpr ErasedStorage(T *pointer_)
Definition function_ref.h:94
constexpr ErasedStorage(T const *const_pointer_)
Definition function_ref.h:97
void(* function_pointer)()
Definition function_ref.h:89
ErasedStorage(T *function_pointer_)
Definition function_ref.h:100