Skip to content

Commit acd6067

Browse files
committed
Make Fn/FnMut/FnOnce constexpr except for operator()
Running can't be constexpr as it does not allow casting a void* to a T*, and we need to do this inside the Invoke function to call the operator() method. To make this constexpr we would not be able to type erase the T* to a void*.
1 parent 074c5d3 commit acd6067

File tree

1 file changed

+38
-61
lines changed

1 file changed

+38
-61
lines changed

subspace/fn/stackfn_defn.h

Lines changed: 38 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ class [[sus_trivial_abi]] Fn<R(CallArgs...)> {
131131
///
132132
/// #[doc.overloads=ctor.fnpointer]
133133
template <__private::FunctionPointer<R, CallArgs...> F>
134-
Fn(F ptr) noexcept {
134+
constexpr Fn(F ptr) noexcept {
135135
::sus::check(ptr != nullptr);
136136
storage_.fnptr = static_cast<void (*)()>(ptr);
137137
invoke_ = &__private::Invoker<F>::template fnptr_call_const<R, CallArgs...>;
@@ -141,25 +141,23 @@ class [[sus_trivial_abi]] Fn<R(CallArgs...)> {
141141
///
142142
/// #[doc.overloads=ctor.lambda]
143143
template <__private::CallableMut<R, CallArgs...> F>
144-
Fn(F&& object) noexcept {
144+
constexpr Fn(F&& object) noexcept {
145145
storage_.object = ::sus::mem::addressof(object);
146146
invoke_ = &__private::Invoker<
147147
std::remove_reference_t<F>>::template object_call_const<R, CallArgs...>;
148148
}
149149

150150
~Fn() noexcept = default;
151151

152-
Fn(Fn&& o) noexcept
152+
constexpr Fn(Fn&& o) noexcept
153153
: storage_(o.storage_),
154154
invoke_(::sus::mem::replace_ptr(o.invoke_, nullptr)) {
155-
// Catch use-after-move.
156-
::sus::check(invoke_);
155+
::sus::check(invoke_); // Catch use-after-move.
157156
}
158-
Fn& operator=(Fn&& o) noexcept {
157+
constexpr Fn& operator=(Fn&& o) noexcept {
159158
storage_ = o.storage_;
160159
invoke_ = ::sus::mem::replace_ptr(o.invoke_, nullptr);
161-
// Catch use-after-move.
162-
::sus::check(invoke_);
160+
::sus::check(invoke_); // Catch use-after-move.
163161
return *this;
164162
}
165163

@@ -168,21 +166,20 @@ class [[sus_trivial_abi]] Fn<R(CallArgs...)> {
168166
Fn& operator=(const Fn&) noexcept = delete;
169167

170168
/// sus::mem::Clone trait.
171-
Fn clone() const {
172-
// Catch use-after-move.
173-
::sus::check(invoke_);
169+
constexpr Fn clone() const {
170+
::sus::check(invoke_); // Catch use-after-move.
174171
return Fn(storage_, invoke_);
175172
}
176173

177174
/// Runs the closure.
178175
inline R operator()(CallArgs... args) const& {
176+
::sus::check(invoke_); // Catch use-after-move.
179177
return (*invoke_)(storage_, ::sus::forward<CallArgs>(args)...);
180178
}
181179

182180
/// Runs and consumes the closure.
183181
inline R operator()(CallArgs... args) && {
184-
// Catch use-after-move.
185-
::sus::check(invoke_);
182+
::sus::check(invoke_); // Catch use-after-move.
186183
return (*::sus::mem::replace_ptr(invoke_, nullptr))(
187184
storage_, ::sus::forward<CallArgs>(args)...);
188185
}
@@ -197,25 +194,14 @@ class [[sus_trivial_abi]] Fn<R(CallArgs...)> {
197194
return Fn(::sus::forward<F>(object));
198195
}
199196

200-
// operator to avoid extra indirections being inserted when converting, since
201-
// otherwise an extra Invoker call would be introduced.
202-
operator FnOnce<R, CallArgs...>() && {
203-
return FnOnce(storage_, ::sus::mem::replace_ptr(invoke_, nullptr));
204-
}
205-
// operator to avoid extra indirections being inserted when converting, since
206-
// otherwise an extra Invoker call would be introduced.
207-
operator FnMut<R, CallArgs...>() && {
208-
return FnMut(storage_, ::sus::mem::replace_ptr(invoke_, nullptr));
209-
}
210-
211197
private:
212198
template <class RR, class... AArgs>
213199
friend class FnOnce;
214200
template <class RR, class... AArgs>
215201
friend class FnMut;
216202

217-
Fn(union __private::Storage storage,
218-
__private::InvokeFnPtr<R, CallArgs...> invoke)
203+
constexpr Fn(union __private::Storage storage,
204+
__private::InvokeFnPtr<R, CallArgs...> invoke)
219205
: storage_(storage), invoke_(invoke) {}
220206

221207
union __private::Storage storage_;
@@ -267,7 +253,7 @@ class [[sus_trivial_abi]] FnMut<R(CallArgs...)> {
267253
///
268254
/// #[doc.overloads=ctor.fnpointer]
269255
template <__private::FunctionPointer<R, CallArgs...> F>
270-
FnMut(F ptr) noexcept {
256+
constexpr FnMut(F ptr) noexcept {
271257
::sus::check(ptr != nullptr);
272258
storage_.fnptr = static_cast<void (*)()>(ptr);
273259
invoke_ = &__private::Invoker<F>::template fnptr_call_mut<R, CallArgs...>;
@@ -277,7 +263,7 @@ class [[sus_trivial_abi]] FnMut<R(CallArgs...)> {
277263
///
278264
/// #[doc.overloads=ctor.lambda]
279265
template <__private::CallableMut<R, CallArgs...> F>
280-
FnMut(F&& object) noexcept {
266+
constexpr FnMut(F&& object) noexcept {
281267
storage_.object = ::sus::mem::addressof(object);
282268
invoke_ = &__private::Invoker<
283269
std::remove_reference_t<F>>::template object_call_mut<R, CallArgs...>;
@@ -288,26 +274,23 @@ class [[sus_trivial_abi]] FnMut<R(CallArgs...)> {
288274
/// Since Fn is callable, FnMut is already constructible from it, but
289275
/// this constructor avoids extra indirections being inserted when converting,
290276
/// since otherwise an extra invoker call would be introduced.
291-
FnMut(Fn<R(CallArgs...)>&& o) noexcept
277+
constexpr FnMut(Fn<R(CallArgs...)>&& o) noexcept
292278
: storage_(o.storage_),
293279
invoke_(::sus::mem::replace_ptr(o.invoke_, nullptr)) {
294-
// Catch use-after-move.
295-
::sus::check(invoke_);
280+
::sus::check(invoke_); // Catch use-after-move.
296281
}
297282

298283
~FnMut() noexcept = default;
299284

300-
FnMut(FnMut&& o) noexcept
285+
constexpr FnMut(FnMut&& o) noexcept
301286
: storage_(o.storage_),
302287
invoke_(::sus::mem::replace_ptr(o.invoke_, nullptr)) {
303-
// Catch use-after-move.
304-
::sus::check(invoke_);
288+
::sus::check(invoke_); // Catch use-after-move.
305289
}
306-
FnMut& operator=(FnMut&& o) noexcept {
290+
constexpr FnMut& operator=(FnMut&& o) noexcept {
307291
storage_ = o.storage_;
308292
invoke_ = ::sus::mem::replace_ptr(o.invoke_, nullptr);
309-
// Catch use-after-move.
310-
::sus::check(invoke_);
293+
::sus::check(invoke_); // Catch use-after-move.
311294
return *this;
312295
}
313296

@@ -316,21 +299,20 @@ class [[sus_trivial_abi]] FnMut<R(CallArgs...)> {
316299
FnMut& operator=(const FnMut&) noexcept = delete;
317300

318301
/// sus::mem::Clone trait.
319-
FnMut clone() const {
320-
// Catch use-after-move.
321-
::sus::check(invoke_);
302+
constexpr FnMut clone() const {
303+
::sus::check(invoke_); // Catch use-after-move.
322304
return FnMut(storage_, invoke_);
323305
}
324306

325307
/// Runs the closure.
326308
inline R operator()(CallArgs... args) & {
309+
::sus::check(invoke_); // Catch use-after-move.
327310
return (*invoke_)(storage_, ::sus::forward<CallArgs>(args)...);
328311
}
329312

330313
/// Runs and consumes the closure.
331314
inline R operator()(CallArgs... args) && {
332-
// Catch use-after-move.
333-
::sus::check(invoke_);
315+
::sus::check(invoke_); // Catch use-after-move.
334316
return (*::sus::mem::replace_ptr(invoke_, nullptr))(
335317
storage_, ::sus::forward<CallArgs>(args)...);
336318
}
@@ -349,7 +331,7 @@ class [[sus_trivial_abi]] FnMut<R(CallArgs...)> {
349331
template <class RR, class... AArgs>
350332
friend class FnOnce;
351333

352-
FnMut(union __private::Storage storage,
334+
constexpr FnMut(union __private::Storage storage,
353335
__private::InvokeFnPtr<R, CallArgs...> invoke)
354336
: storage_(storage), invoke_(invoke) {}
355337

@@ -401,7 +383,7 @@ class [[sus_trivial_abi]] FnOnce<R(CallArgs...)> {
401383
///
402384
/// #[doc.overloads=ctor.fnpointer]
403385
template <__private::FunctionPointer<R, CallArgs...> F>
404-
FnOnce(F ptr) noexcept {
386+
constexpr FnOnce(F ptr) noexcept {
405387
::sus::check(ptr != nullptr);
406388
storage_.fnptr = static_cast<void (*)()>(ptr);
407389
invoke_ = &__private::Invoker<F>::template fnptr_call_mut<R, CallArgs...>;
@@ -411,7 +393,7 @@ class [[sus_trivial_abi]] FnOnce<R(CallArgs...)> {
411393
///
412394
/// #[doc.overloads=ctor.lambda]
413395
template <__private::CallableMut<R, CallArgs...> F>
414-
FnOnce(F&& object) noexcept {
396+
constexpr FnOnce(F&& object) noexcept {
415397
storage_.object = ::sus::mem::addressof(object);
416398
invoke_ = &__private::Invoker<
417399
std::remove_reference_t<F>>::template object_call_mut<R, CallArgs...>;
@@ -422,38 +404,34 @@ class [[sus_trivial_abi]] FnOnce<R(CallArgs...)> {
422404
/// Since FnMut is callable, FnOnce is already constructible from it, but
423405
/// this constructor avoids extra indirections being inserted when converting,
424406
/// since otherwise an extra invoker call would be introduced.
425-
FnOnce(FnMut<R(CallArgs...)>&& o) noexcept
407+
constexpr FnOnce(FnMut<R(CallArgs...)>&& o) noexcept
426408
: storage_(o.storage_),
427409
invoke_(::sus::mem::replace_ptr(o.invoke_, nullptr)) {
428-
// Catch use-after-move.
429-
::sus::check(invoke_);
410+
::sus::check(invoke_); // Catch use-after-move.
430411
}
431412

432413
/// Construction from Fn.
433414
///
434415
/// Since Fn is callable, FnOnce is already constructible from it, but
435416
/// this constructor avoids extra indirections being inserted when converting,
436417
/// since otherwise an extra invoker call would be introduced.
437-
FnOnce(Fn<R(CallArgs...)>&& o) noexcept
418+
constexpr FnOnce(Fn<R(CallArgs...)>&& o) noexcept
438419
: storage_(o.storage_),
439420
invoke_(::sus::mem::replace_ptr(o.invoke_, nullptr)) {
440-
// Catch use-after-move.
441-
::sus::check(invoke_);
421+
::sus::check(invoke_); // Catch use-after-move.
442422
}
443423

444424
~FnOnce() noexcept = default;
445425

446-
FnOnce(FnOnce&& o) noexcept
426+
constexpr FnOnce(FnOnce&& o) noexcept
447427
: storage_(o.storage_),
448428
invoke_(::sus::mem::replace_ptr(o.invoke_, nullptr)) {
449-
// Catch use-after-move.
450-
::sus::check(invoke_);
429+
::sus::check(invoke_); // Catch use-after-move.
451430
}
452-
FnOnce& operator=(FnOnce&& o) noexcept {
431+
constexpr FnOnce& operator=(FnOnce&& o) noexcept {
453432
storage_ = o.storage_;
454433
invoke_ = ::sus::mem::replace_ptr(o.invoke_, nullptr);
455-
// Catch use-after-move.
456-
::sus::check(invoke_);
434+
::sus::check(invoke_); // Catch use-after-move.
457435
return *this;
458436
}
459437

@@ -463,8 +441,7 @@ class [[sus_trivial_abi]] FnOnce<R(CallArgs...)> {
463441

464442
/// Runs and consumes the closure.
465443
inline R operator()(CallArgs... args) && {
466-
// Catch use-after-move.
467-
::sus::check(invoke_);
444+
::sus::check(invoke_); // Catch use-after-move.
468445
return (*::sus::mem::replace_ptr(invoke_, nullptr))(
469446
storage_, ::sus::forward<CallArgs>(args)...);
470447
}
@@ -483,8 +460,8 @@ class [[sus_trivial_abi]] FnOnce<R(CallArgs...)> {
483460
friend FnMut<R, CallArgs...>;
484461
friend Fn<R, CallArgs...>;
485462

486-
FnOnce(union __private::Storage storage,
487-
__private::InvokeFnPtr<R, CallArgs...> invoke)
463+
constexpr FnOnce(union __private::Storage storage,
464+
__private::InvokeFnPtr<R, CallArgs...> invoke)
488465
: storage_(storage), invoke_(invoke) {}
489466

490467
union __private::Storage storage_;

0 commit comments

Comments
 (0)