Skip to content

Commit 4441e71

Browse files
committed
Remove a level of indirection in Fn/Mut/Once
1 parent e9aca46 commit 4441e71

File tree

1 file changed

+82
-103
lines changed

1 file changed

+82
-103
lines changed

subspace/fn/stackfn_defn.h

Lines changed: 82 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414

1515
#pragma once
1616

17+
#include <stdint.h>
18+
1719
#include "subspace/fn/callable.h"
1820
#include "subspace/mem/addressof.h"
1921
#include "subspace/mem/forward.h"
@@ -41,25 +43,20 @@ class SFn;
4143

4244
namespace __private {
4345

44-
template <class R, class... Args>
45-
struct CallVtable {
46-
R (*call)(void* p, Args... args);
47-
};
48-
4946
template <class F>
5047
struct Invoker {
5148
template <class R, class... Args>
52-
static R call_mut(void* p, Args... args) {
53-
F& f = *static_cast<F*>(p);
49+
static R call_mut(uintptr_t p, Args... args) {
50+
F& f = *reinterpret_cast<F*>(p);
5451
return f(::sus::forward<Args>(args)...);
5552
}
5653

5754
template <class R, class... Args>
58-
static R call_const(void* p, Args... args) {
59-
const F& f = *static_cast<const F*>(p);
55+
static R call_const(uintptr_t p, Args... args) {
56+
const F& f = *reinterpret_cast<const F*>(p);
6057
return f(::sus::forward<Args>(args)...);
6158
}
62-
}; // namespace __private
59+
};
6360

6461
} // namespace __private
6562

@@ -96,42 +93,36 @@ class [[sus_trivial_abi]] SFn<R(CallArgs...)> {
9693
/// #[doc.overloads=ctor.fnpointer]
9794
template <::sus::fn::callable::FunctionPointerMatches<R, CallArgs...> F>
9895
SFn(F ptr) noexcept {
99-
::sus::check(ptr != nullptr);
100-
callable_ = static_cast<void*>(ptr);
101-
static auto vtable = __private::CallVtable<R, CallArgs...>{
102-
.call = &__private::Invoker<
103-
std::remove_reference_t<F>>::template call_const<R, CallArgs...>,
104-
};
105-
vtable_ = &vtable;
96+
::sus::check(+ptr != nullptr);
97+
callable_ = reinterpret_cast<uintptr_t>(+ptr);
98+
invoke_ = &__private::Invoker<
99+
std::remove_reference_t<F>>::template call_const<R, CallArgs...>;
106100
}
107101

108102
/// Construction from a capturing lambda or other callable object.
109103
///
110104
/// #[doc.overloads=ctor.lambda]
111105
template <::sus::fn::callable::CallableObjectReturns<R, CallArgs...> F>
112106
SFn(F&& object) noexcept {
113-
callable_ = static_cast<void*>(::sus::mem::addressof(object));
114-
static auto vtable = __private::CallVtable<R, CallArgs...>{
115-
.call = &__private::Invoker<
116-
std::remove_reference_t<F>>::template call_const<R, CallArgs...>,
117-
};
118-
vtable_ = &vtable;
107+
callable_ = reinterpret_cast<uintptr_t>(::sus::mem::addressof(object));
108+
invoke_ = &__private::Invoker<
109+
std::remove_reference_t<F>>::template call_const<R, CallArgs...>;
119110
}
120111

121112
~SFn() noexcept = default;
122113

123114
SFn(SFn&& o) noexcept
124-
: callable_(::sus::mem::replace_ptr(o.callable_, nullptr)),
125-
// Not setting `o.vtable_` to nullptr, as vtable_ as nullptr is its
115+
: callable_(::sus::mem::replace(o.callable_, uintptr_t{0})),
116+
// Not setting `o.invoke_` to nullptr, as invoke_ as nullptr is its
126117
// never-value.
127-
vtable_(o.vtable_) {
118+
invoke_(o.invoke_) {
128119
::sus::check(callable_); // Catch use-after-move.
129120
}
130121
SFn& operator=(SFn&& o) noexcept {
131-
callable_ = ::sus::mem::replace_ptr(o.callable_, nullptr);
132-
// Not setting `o.vtable_` to nullptr, as vtable_ as nullptr is its
122+
callable_ = ::sus::mem::replace(o.callable_, uintptr_t{0});
123+
// Not setting `o.invoke_` to nullptr, as invoke_ as nullptr is its
133124
// never-value.
134-
vtable_ = o.vtable_;
125+
invoke_ = o.invoke_;
135126
::sus::check(callable_); // Catch use-after-move.
136127
return *this;
137128
}
@@ -143,19 +134,19 @@ class [[sus_trivial_abi]] SFn<R(CallArgs...)> {
143134
/// sus::mem::Clone trait.
144135
SFn clone() const {
145136
::sus::check(callable_); // Catch use-after-move.
146-
return SFn(callable_, vtable_);
137+
return SFn(callable_, invoke_);
147138
}
148139

149140
/// Runs the closure.
150141
inline R operator()(CallArgs... args) const& {
151-
return vtable_->call(callable_, ::sus::forward<CallArgs>(args)...);
142+
return (*invoke_)(callable_, ::sus::forward<CallArgs>(args)...);
152143
}
153144

154145
/// Runs and consumes the closure.
155146
inline R operator()(CallArgs... args) && {
156147
::sus::check(callable_); // Catch use-after-move.
157-
return vtable_->call(::sus::mem::replace_ptr(callable_, nullptr),
158-
::sus::forward<CallArgs>(args)...);
148+
return (*invoke_)(::sus::mem::replace(callable_, uintptr_t{0}),
149+
::sus::forward<CallArgs>(args)...);
159150
}
160151

161152
/// `sus::construct::From` trait implementation.
@@ -171,12 +162,12 @@ class [[sus_trivial_abi]] SFn<R(CallArgs...)> {
171162
// operator to avoid extra indirections being inserted when converting, since
172163
// otherwise an extra Invoker call would be introduced.
173164
operator SFnOnce<R, CallArgs...>() && {
174-
return SFnOnce(::sus::mem::replace(callable_, nullptr), vtable_);
165+
return SFnOnce(::sus::mem::replace(callable_, uintptr_t{0}), invoke_);
175166
}
176167
// operator to avoid extra indirections being inserted when converting, since
177168
// otherwise an extra Invoker call would be introduced.
178169
operator SFnMut<R, CallArgs...>() && {
179-
return SFnMut(::sus::mem::replace(callable_, nullptr), vtable_);
170+
return SFnMut(::sus::mem::replace(callable_, uintptr_t{0}), invoke_);
180171
}
181172

182173
private:
@@ -185,15 +176,15 @@ class [[sus_trivial_abi]] SFn<R(CallArgs...)> {
185176
template <class RR, class... AArgs>
186177
friend class SFnMut;
187178

188-
SFn(void* callable, __private::CallVtable<R, CallArgs...>* vtable)
189-
: callable_(callable), vtable_(vtable) {}
179+
SFn(uintptr_t callable, R (*invoke)(uintptr_t p, CallArgs... args))
180+
: callable_(callable), invoke_(invoke) {}
190181

191-
void* callable_;
192-
__private::CallVtable<R, CallArgs...>* vtable_;
182+
uintptr_t callable_;
183+
R (*invoke_)(uintptr_t p, CallArgs... args);
193184

194185
sus_class_trivially_relocatable(::sus::marker::unsafe_fn, decltype(callable_),
195-
decltype(vtable_));
196-
sus_class_never_value_field(::sus::marker::unsafe_fn, SFn, vtable_, nullptr,
186+
decltype(invoke_));
187+
sus_class_never_value_field(::sus::marker::unsafe_fn, SFn, invoke_, nullptr,
197188
nullptr);
198189

199190
protected:
@@ -233,26 +224,20 @@ class [[sus_trivial_abi]] SFnMut<R(CallArgs...)> {
233224
/// #[doc.overloads=ctor.fnpointer]
234225
template <::sus::fn::callable::FunctionPointerMatches<R, CallArgs...> F>
235226
SFnMut(F ptr) noexcept {
236-
::sus::check(ptr != nullptr);
237-
callable_ = static_cast<void*>(ptr);
238-
static auto vtable = __private::CallVtable<R, CallArgs...>{
239-
.call = &__private::Invoker<
240-
std::remove_reference_t<F>>::template call_mut<R, CallArgs...>,
241-
};
242-
vtable_ = &vtable;
227+
::sus::check(+ptr != nullptr);
228+
callable_ = reinterpret_cast<uintptr_t>(+ptr);
229+
invoke_ = &__private::Invoker<
230+
std::remove_reference_t<F>>::template call_mut<R, CallArgs...>;
243231
}
244232

245233
/// Construction from a capturing lambda or other callable object.
246234
///
247235
/// #[doc.overloads=ctor.lambda]
248236
template <::sus::fn::callable::CallableObjectReturns<R, CallArgs...> F>
249237
SFnMut(F&& object) noexcept {
250-
callable_ = static_cast<void*>(::sus::mem::addressof(object));
251-
static auto vtable = __private::CallVtable<R, CallArgs...>{
252-
.call = &__private::Invoker<
253-
std::remove_reference_t<F>>::template call_mut<R, CallArgs...>,
254-
};
255-
vtable_ = &vtable;
238+
callable_ = reinterpret_cast<uintptr_t>(::sus::mem::addressof(object));
239+
invoke_ = &__private::Invoker<
240+
std::remove_reference_t<F>>::template call_mut<R, CallArgs...>;
256241
}
257242

258243
/// Construction from SFn.
@@ -261,25 +246,25 @@ class [[sus_trivial_abi]] SFnMut<R(CallArgs...)> {
261246
/// this constructor avoids extra indirections being inserted when converting,
262247
/// since otherwise an extra invoker call would be introduced.
263248
SFnMut(SFn<R(CallArgs...)>&& o) noexcept
264-
: callable_(::sus::mem::replace_ptr(o.callable_, nullptr)),
265-
vtable_(o.vtable_) {
249+
: callable_(::sus::mem::replace(o.callable_, uintptr_t{0})),
250+
invoke_(o.invoke_) {
266251
::sus::check(callable_); // Catch use-after-move.
267252
}
268253

269254
~SFnMut() noexcept = default;
270255

271256
SFnMut(SFnMut&& o) noexcept
272-
: callable_(::sus::mem::replace_ptr(o.callable_, nullptr)),
273-
// Not setting `o.vtable_` to nullptr, as vtable_ as nullptr is its
257+
: callable_(::sus::mem::replace(o.callable_, uintptr_t{0})),
258+
// Not setting `o.invoke_` to nullptr, as invoke_ as nullptr is its
274259
// never-value.
275-
vtable_(o.vtable_) {
260+
invoke_(o.invoke_) {
276261
::sus::check(callable_); // Catch use-after-move.
277262
}
278263
SFnMut& operator=(SFnMut&& o) noexcept {
279-
callable_ = ::sus::mem::replace_ptr(o.callable_, nullptr);
280-
// Not setting `o.vtable_` to nullptr, as vtable_ as nullptr is its
264+
callable_ = ::sus::mem::replace(o.callable_, uintptr_t{0});
265+
// Not setting `o.invoke_` to nullptr, as invoke_ as nullptr is its
281266
// never-value.
282-
vtable_ = o.vtable_;
267+
invoke_ = o.invoke_;
283268
::sus::check(callable_); // Catch use-after-move.
284269
return *this;
285270
}
@@ -291,19 +276,19 @@ class [[sus_trivial_abi]] SFnMut<R(CallArgs...)> {
291276
/// sus::mem::Clone trait.
292277
SFnMut clone() const {
293278
::sus::check(callable_); // Catch use-after-move.
294-
return SFnMut(callable_, vtable_);
279+
return SFnMut(callable_, invoke_);
295280
}
296281

297282
/// Runs the closure.
298283
inline R operator()(CallArgs... args) & {
299-
return vtable_->call(callable_, ::sus::forward<CallArgs>(args)...);
284+
return (*invoke_)(callable_, ::sus::forward<CallArgs>(args)...);
300285
}
301286

302287
/// Runs and consumes the closure.
303288
inline R operator()(CallArgs... args) && {
304289
::sus::check(callable_); // Catch use-after-move.
305-
return vtable_->call(::sus::mem::replace_ptr(callable_, nullptr),
306-
::sus::forward<CallArgs>(args)...);
290+
return (*invoke_)(::sus::mem::replace(callable_, uintptr_t{0}),
291+
::sus::forward<CallArgs>(args)...);
307292
}
308293

309294
/// `sus::construct::From` trait implementation.
@@ -320,15 +305,15 @@ class [[sus_trivial_abi]] SFnMut<R(CallArgs...)> {
320305
template <class RR, class... AArgs>
321306
friend class SFnOnce;
322307

323-
SFnMut(void* callable, __private::CallVtable<R, CallArgs...>* vtable)
324-
: callable_(callable), vtable_(vtable) {}
308+
SFnMut(uintptr_t callable, R (*invoke)(uintptr_t p, CallArgs... args))
309+
: callable_(callable), invoke_(invoke) {}
325310

326-
void* callable_;
327-
__private::CallVtable<R, CallArgs...>* vtable_;
311+
uintptr_t callable_;
312+
R (*invoke_)(uintptr_t p, CallArgs... args);
328313

329314
sus_class_trivially_relocatable(::sus::marker::unsafe_fn, decltype(callable_),
330-
decltype(vtable_));
331-
sus_class_never_value_field(::sus::marker::unsafe_fn, SFnMut, vtable_,
315+
decltype(invoke_));
316+
sus_class_never_value_field(::sus::marker::unsafe_fn, SFnMut, invoke_,
332317
nullptr, nullptr);
333318

334319
protected:
@@ -367,26 +352,20 @@ class [[sus_trivial_abi]] SFnOnce<R(CallArgs...)> {
367352
/// #[doc.overloads=ctor.fnpointer]
368353
template <::sus::fn::callable::FunctionPointerMatches<R, CallArgs...> F>
369354
SFnOnce(F ptr) noexcept {
370-
::sus::check(ptr != nullptr);
371-
callable_ = static_cast<void*>(ptr);
372-
static auto vtable = __private::CallVtable<R, CallArgs...>{
373-
.call = &__private::Invoker<
374-
std::remove_reference_t<F>>::template call_mut<R, CallArgs...>,
375-
};
376-
vtable_ = &vtable;
355+
::sus::check(+ptr != nullptr);
356+
callable_ = reinterpret_cast<uintptr_t>(+ptr);
357+
invoke_ = &__private::Invoker<
358+
std::remove_reference_t<F>>::template call_mut<R, CallArgs...>;
377359
}
378360

379361
/// Construction from a capturing lambda or other callable object.
380362
///
381363
/// #[doc.overloads=ctor.lambda]
382364
template <::sus::fn::callable::CallableObjectReturns<R, CallArgs...> F>
383365
SFnOnce(F&& object) noexcept {
384-
callable_ = static_cast<void*>(::sus::mem::addressof(object));
385-
static auto vtable = __private::CallVtable<R, CallArgs...>{
386-
.call = &__private::Invoker<
387-
std::remove_reference_t<F>>::template call_mut<R, CallArgs...>,
388-
};
389-
vtable_ = &vtable;
366+
callable_ = reinterpret_cast<uintptr_t>(::sus::mem::addressof(object));
367+
invoke_ = &__private::Invoker<
368+
std::remove_reference_t<F>>::template call_mut<R, CallArgs...>;
390369
}
391370

392371
/// Construction from SFnMut.
@@ -395,8 +374,8 @@ class [[sus_trivial_abi]] SFnOnce<R(CallArgs...)> {
395374
/// this constructor avoids extra indirections being inserted when converting,
396375
/// since otherwise an extra invoker call would be introduced.
397376
SFnOnce(SFnMut<R(CallArgs...)>&& o) noexcept
398-
: callable_(::sus::mem::replace_ptr(o.callable_, nullptr)),
399-
vtable_(o.vtable_) {
377+
: callable_(::sus::mem::replace(o.callable_, uintptr_t{0})),
378+
invoke_(o.invoke_) {
400379
::sus::check(callable_); // Catch use-after-move.
401380
}
402381

@@ -406,25 +385,25 @@ class [[sus_trivial_abi]] SFnOnce<R(CallArgs...)> {
406385
/// this constructor avoids extra indirections being inserted when converting,
407386
/// since otherwise an extra invoker call would be introduced.
408387
SFnOnce(SFn<R(CallArgs...)>&& o) noexcept
409-
: callable_(::sus::mem::replace_ptr(o.callable_, nullptr)),
410-
vtable_(o.vtable_) {
388+
: callable_(::sus::mem::replace(o.callable_, uintptr_t{0})),
389+
invoke_(o.invoke_) {
411390
::sus::check(callable_); // Catch use-after-move.
412391
}
413392

414393
~SFnOnce() noexcept = default;
415394

416395
SFnOnce(SFnOnce&& o) noexcept
417-
: callable_(::sus::mem::replace_ptr(o.callable_, nullptr)),
418-
// Not setting `o.vtable_` to nullptr, as vtable_ as nullptr is its
396+
: callable_(::sus::mem::replace(o.callable_, uintptr_t{0})),
397+
// Not setting `o.invoke_` to nullptr, as invoke_ as nullptr is its
419398
// never-value.
420-
vtable_(o.vtable_) {
399+
invoke_(o.invoke_) {
421400
::sus::check(callable_); // Catch use-after-move.
422401
}
423402
SFnOnce& operator=(SFnOnce&& o) noexcept {
424-
callable_ = ::sus::mem::replace_ptr(o.callable_, nullptr);
425-
// Not setting `o.vtable_` to nullptr, as vtable_ as nullptr is its
403+
callable_ = ::sus::mem::replace(o.callable_, uintptr_t{0});
404+
// Not setting `o.invoke_` to nullptr, as invoke_ as nullptr is its
426405
// never-value.
427-
vtable_ = o.vtable_;
406+
invoke_ = o.invoke_;
428407
::sus::check(callable_); // Catch use-after-move.
429408
return *this;
430409
}
@@ -436,8 +415,8 @@ class [[sus_trivial_abi]] SFnOnce<R(CallArgs...)> {
436415
/// Runs and consumes the closure.
437416
inline R operator()(CallArgs... args) && {
438417
::sus::check(callable_); // Catch use-after-move.
439-
return vtable_->call(::sus::mem::replace_ptr(callable_, nullptr),
440-
::sus::forward<CallArgs>(args)...);
418+
return (*invoke_)(::sus::mem::replace(callable_, uintptr_t{0}),
419+
::sus::forward<CallArgs>(args)...);
441420
}
442421

443422
/// `sus::construct::From` trait implementation.
@@ -454,15 +433,15 @@ class [[sus_trivial_abi]] SFnOnce<R(CallArgs...)> {
454433
friend SFnMut<R, CallArgs...>;
455434
friend SFn<R, CallArgs...>;
456435

457-
SFnOnce(void* callable, __private::CallVtable<R, CallArgs...>* vtable)
458-
: callable_(callable), vtable_(vtable) {}
436+
SFnOnce(uintptr_t callable, R (*invoke)(uintptr_t p, CallArgs... args))
437+
: callable_(callable), invoke_(invoke) {}
459438

460-
void* callable_;
461-
__private::CallVtable<R, CallArgs...>* vtable_;
439+
uintptr_t callable_;
440+
R (*invoke_)(uintptr_t p, CallArgs... args);
462441

463442
sus_class_trivially_relocatable(::sus::marker::unsafe_fn, decltype(callable_),
464-
decltype(vtable_));
465-
sus_class_never_value_field(::sus::marker::unsafe_fn, SFnOnce, vtable_,
443+
decltype(invoke_));
444+
sus_class_never_value_field(::sus::marker::unsafe_fn, SFnOnce, invoke_,
466445
nullptr, nullptr);
467446

468447
protected:

0 commit comments

Comments
 (0)