14
14
15
15
#pragma once
16
16
17
- #include " subspace/fn/callable.h"
17
+ #include " subspace/fn/__private/callable_types.h"
18
+ #include " subspace/fn/__private/fn_ref_invoker.h"
18
19
#include " subspace/macros/lifetimebound.h"
19
20
#include " subspace/mem/addressof.h"
20
21
#include " subspace/mem/forward.h"
@@ -31,110 +32,22 @@ class FnMutRef;
31
32
template <class R , class ... Args>
32
33
class FnRef ;
33
34
34
- // TODO: Consider generic lambdas, it should be possible to bind them into
35
- // FnOnceRef/FnMutRef/FnRef?
36
- // Example:
37
- // ```
38
- // auto even = [](const auto& i) { return i % 2 == 0; };
39
- // auto r0 = sus::Array<int, 11>::with_values(0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
40
- // 10);
41
- // auto result = r0.iter().filter(even);
42
- // ```
43
-
44
- namespace __private {
45
-
46
- union Storage {
47
- void (*fnptr)();
48
- void * object;
49
- };
50
-
51
- template <class F >
52
- struct Invoker {
53
- template <class R , class ... Args>
54
- static R fnptr_call_mut (const union Storage& s, Args... args) {
55
- F f = reinterpret_cast <F>(s.fnptr );
56
- return (*f)(::sus::forward<Args>(args)...);
57
- }
58
-
59
- template <class R , class ... Args>
60
- static R object_call_mut (const union Storage& s, Args... args) {
61
- F& f = *static_cast <F*>(s.object );
62
- return f (::sus::forward<Args>(args)...);
63
- }
64
-
65
- template <class R , class ... Args>
66
- static R object_call_once (const union Storage& s, Args... args) {
67
- F& f = *static_cast <F*>(s.object );
68
- return ::sus::move (f)(::sus::forward<Args>(args)...);
69
- }
70
-
71
- template <class R , class ... Args>
72
- static R fnptr_call_const (const union Storage& s, Args... args) {
73
- const F f = reinterpret_cast <const F>(s.fnptr );
74
- return (*f)(::sus::forward<Args>(args)...);
75
- }
76
-
77
- template <class R , class ... Args>
78
- static R object_call_const (const union Storage& s, Args... args) {
79
- const F& f = *static_cast <const F*>(s.object );
80
- return f (::sus::forward<Args>(args)...);
81
- }
82
- };
83
-
84
- template <class R , class ... CallArgs>
85
- using InvokeFnPtr = R (*)(const union Storage& s, CallArgs... args);
86
-
87
- template <class F , class R , class ... Args>
88
- concept FunctionPointer =
89
- std::is_pointer_v<std::decay_t <F>> && requires (F f, Args... args) {
90
- { (*f)(args...) } -> std::convertible_to<R>;
91
- };
92
-
93
- template <class T >
94
- concept IsFunctionPointer =
95
- std::is_pointer_v<T> && std::is_function_v<std::remove_pointer_t <T>>;
96
-
97
- template <class F >
98
- concept ConvertsToFunctionPointer = requires (F f) {
99
- { +f } -> IsFunctionPointer;
100
- };
101
-
102
- template <class F , class R , class ... Args>
103
- concept CallableOnceMut =
104
- !FunctionPointer<F, R, Args...> && requires (F && f, Args... args) {
105
- { ::sus::move (f)(args...) } -> std::convertible_to<R>;
106
- };
107
-
108
- template <class F , class R , class ... Args>
109
- concept CallableMut =
110
- !FunctionPointer<F, R, Args...> && requires (F & f, Args... args) {
111
- { f (args...) } -> std::convertible_to<R>;
112
- };
113
-
114
- template <class F , class R , class ... Args>
115
- concept CallableConst =
116
- !FunctionPointer<F, R, Args...> && requires (const F& f, Args... args) {
117
- { f (args...) } -> std::convertible_to<R>;
118
- };
119
-
120
- } // namespace __private
121
-
122
35
// / A closure that erases the type of the internal callable object (lambda). A
123
36
// / FnMutRef may be called multiple times, and holds a const callable object, so
124
37
// / it will return the same value each call with the same inputs.
125
38
// /
126
- // / FnRef can be used as a FnMutRef, which can be used as a FnOnceRef. Lambdas can be
127
- // / converted into a FnOnceRef, FnMutRef, or FnRef directly.
39
+ // / FnRef can be used as a FnMutRef, which can be used as a FnOnceRef. Lambdas
40
+ // / can be converted into a FnOnceRef, FnMutRef, or FnRef directly.
128
41
// /
129
- // / FnOnceRef, FnMutRef and FnRef are only safe to appear as lvalues when they are a
130
- // / function parameter, and a clang-tidy check is provided to enforce this. They
131
- // / only hold a reference to the underlying lambda so they must not outlive the
132
- // / lambda.
42
+ // / FnOnceRef, FnMutRef and FnRef are only safe to appear as lvalues when they
43
+ // / are a function parameter, and a clang-tidy check is provided to enforce
44
+ // / this. They only hold a reference to the underlying lambda so they must not
45
+ // / outlive the lambda.
133
46
// /
134
47
// / # Why can a "const" FnRef convert to a mutable FnMutRef or FnOnceRef?
135
48
// /
136
- // / A FnMutRef or FnOnceRef is _allowed_ to mutate its storage, but a "const" FnRef
137
- // / closure would just choose not to do so.
49
+ // / A FnMutRef or FnOnceRef is _allowed_ to mutate its storage, but a "const"
50
+ // / FnRef closure would just choose not to do so.
138
51
// /
139
52
// / However, a `const FnRef` requires that the storage is not mutated, so it is
140
53
// / not useful if converted to a `const FnMutRef` or `const FnOnceRef` which are
@@ -218,9 +131,9 @@ class [[sus_trivial_abi]] FnRef<R(CallArgs...)> {
218
131
219
132
// / `sus::construct::From` trait implementation.
220
133
// /
221
- // / FnRef satisfies `From<T>` for the same types that it is constructible from:
222
- // / function pointers that exactly match its own signature, and const-callable
223
- // / objects (lambdas) that are compatible with its signature.
134
+ // / FnRef satisfies `From<T>` for the same types that it is constructible
135
+ // / from: function pointers that exactly match its own signature, and
136
+ // / const-callable objects (lambdas) that are compatible with its signature.
224
137
constexpr static auto from (
225
138
__private::FunctionPointer<R, CallArgs...> auto ptr) noexcept {
226
139
return FnRef (ptr);
@@ -237,10 +150,12 @@ class [[sus_trivial_abi]] FnRef<R(CallArgs...)> {
237
150
friend class FnMutRef ;
238
151
239
152
constexpr FnRef (union __private::Storage storage,
240
- __private::InvokeFnPtr<R, CallArgs...> invoke)
153
+ __private::InvokeFnPtr<R, CallArgs...> invoke)
241
154
: storage_ (storage), invoke_ (invoke) {}
242
155
243
156
union __private::Storage storage_;
157
+ // / The `invoke_` pointer is set to null to indicate the FnRef is moved-from.
158
+ // / It uses another pointer value as its never-value.
244
159
__private::InvokeFnPtr<R, CallArgs...> invoke_;
245
160
246
161
// A function pointer to use as a never-value for InvokeFnPointer.
@@ -261,18 +176,18 @@ class [[sus_trivial_abi]] FnRef<R(CallArgs...)> {
261
176
// / may mutate internal state. A FnMutRef may be called multiple times, and may
262
177
// / return a different value on each call with the same inputs.
263
178
// /
264
- // / FnRef can be used as a FnMutRef, which can be used as a FnOnceRef. Lambdas can be
265
- // / converted into a FnOnceRef, FnMutRef, or FnRef directly.
179
+ // / FnRef can be used as a FnMutRef, which can be used as a FnOnceRef. Lambdas
180
+ // / can be converted into a FnOnceRef, FnMutRef, or FnRef directly.
266
181
// /
267
- // / FnOnceRef, FnMutRef and FnRef are only safe to appear as lvalues when they are a
268
- // / function parameter, and a clang-tidy check is provided to enforce this. They
269
- // / only hold a reference to the underlying lambda so they must not outlive the
270
- // / lambda.
182
+ // / FnOnceRef, FnMutRef and FnRef are only safe to appear as lvalues when they
183
+ // / are a function parameter, and a clang-tidy check is provided to enforce
184
+ // / this. They only hold a reference to the underlying lambda so they must not
185
+ // / outlive the lambda.
271
186
// /
272
187
// / # Why can a "const" FnRef convert to a mutable FnMutRef or FnOnceRef?
273
188
// /
274
- // / A FnMutRef or FnOnceRef is _allowed_ to mutate its storage, but a "const" FnRef
275
- // / closure would just choose not to do so.
189
+ // / A FnMutRef or FnOnceRef is _allowed_ to mutate its storage, but a "const"
190
+ // / FnRef closure would just choose not to do so.
276
191
// /
277
192
// / However, a `const FnRef` requires that the storage is not mutated, so it is
278
193
// / not useful if converted to a `const FnMutRef` or `const FnOnceRef` which are
@@ -384,10 +299,12 @@ class [[sus_trivial_abi]] FnMutRef<R(CallArgs...)> {
384
299
friend class FnOnceRef ;
385
300
386
301
constexpr FnMutRef (union __private::Storage storage,
387
- __private::InvokeFnPtr<R, CallArgs...> invoke)
302
+ __private::InvokeFnPtr<R, CallArgs...> invoke)
388
303
: storage_ (storage), invoke_ (invoke) {}
389
304
390
305
union __private::Storage storage_;
306
+ // / The `invoke_` pointer is set to null to indicate the `FnMutRef` is
307
+ // / moved-from. It uses another pointer value as its never-value.
391
308
__private::InvokeFnPtr<R, CallArgs...> invoke_;
392
309
393
310
// A function pointer to use as a never-value for InvokeFnPointer.
@@ -407,18 +324,18 @@ class [[sus_trivial_abi]] FnMutRef<R(CallArgs...)> {
407
324
// / A closure that erases the type of the internal callable object (lambda). A
408
325
// / FnOnceRef may only be called a single time.
409
326
// /
410
- // / FnRef can be used as a FnMutRef, which can be used as a FnOnceRef. Lambdas can be
411
- // / converted into a FnOnceRef, FnMutRef, or FnRef directly.
327
+ // / FnRef can be used as a FnMutRef, which can be used as a FnOnceRef. Lambdas
328
+ // / can be converted into a FnOnceRef, FnMutRef, or FnRef directly.
412
329
// /
413
- // / FnOnceRef, FnMutRef and FnRef are only safe to appear as lvalues when they are a
414
- // / function parameter, and a clang-tidy check is provided to enforce this. They
415
- // / only hold a reference to the underlying lambda so they must not outlive the
416
- // / lambda.
330
+ // / FnOnceRef, FnMutRef and FnRef are only safe to appear as lvalues when they
331
+ // / are a function parameter, and a clang-tidy check is provided to enforce
332
+ // / this. They only hold a reference to the underlying lambda so they must not
333
+ // / outlive the lambda.
417
334
// /
418
335
// / # Why can a "const" FnRef convert to a mutable FnMutRef or FnOnceRef?
419
336
// /
420
- // / A FnMutRef or FnOnceRef is _allowed_ to mutate its storage, but a "const" FnRef
421
- // / closure would just choose not to do so.
337
+ // / A FnMutRef or FnOnceRef is _allowed_ to mutate its storage, but a "const"
338
+ // / FnRef closure would just choose not to do so.
422
339
// /
423
340
// / However, a `const FnRef` requires that the storage is not mutated, so it is
424
341
// / not useful if converted to a `const FnMutRef` or `const FnOnceRef` which are
@@ -465,9 +382,9 @@ class [[sus_trivial_abi]] FnOnceRef<R(CallArgs...)> {
465
382
466
383
// / Construction from FnMutRef.
467
384
// /
468
- // / Since FnMutRef is callable, FnOnceRef is already constructible from it, but
469
- // / this constructor avoids extra indirections being inserted when converting,
470
- // / since otherwise an extra invoker call would be introduced.
385
+ // / Since FnMutRef is callable, FnOnceRef is already constructible from it,
386
+ // / but this constructor avoids extra indirections being inserted when
387
+ // / converting, since otherwise an extra invoker call would be introduced.
471
388
constexpr FnOnceRef (FnMutRef<R (CallArgs...)>&& o sus_lifetimebound) noexcept
472
389
: storage_ (o.storage_ ),
473
390
invoke_ (::sus::mem::replace_ptr (o.invoke_ , nullptr )) {
@@ -574,6 +491,8 @@ class [[sus_trivial_abi]] FnOnceRef<R(CallArgs...)> {
574
491
: storage_ (storage), invoke_ (invoke) {}
575
492
576
493
union __private::Storage storage_;
494
+ // / The `invoke_` pointer is set to null to indicate the FnOnceRef is
495
+ // / moved-from. It uses another pointer value as its never-value.
577
496
__private::InvokeFnPtr<R, CallArgs...> invoke_;
578
497
579
498
// A function pointer to use as a never-value for InvokeFnPointer.
0 commit comments