1#pragma once
2
3// A delegate is a wrapper around a pointer to member function or a lambda function.
4//
5// IDelegates: interface types.
6// Delegates: implementations of delegates for pointer to member functions (only).
7// LambdaDelegates: implementations of delegates for lambda functions (and more generally functors).
8// AnyDelegates: type-erased type that can store any Delegate or LambdaDelegate.
9//
10// Unlike std::function or inplace_function, delegates cannot wrap functions with arbitrary
11// signatures. Each category of delegate has several variants:
12//
13// - XDelegate (no argument, no return value),
14// - XDelegateR (no argument),
15// - XDelegate1 (1 argument, no return value)
16// - XDelegate1R (1 argument)
17// - XDelegate2 (2 argument, no return value)
18// - XDelegate2R (2 arguments)
19//
20// To make a lambda delegate, use the makeLambdaDelegate functions, which will return a
21// LambdaDelegate with most template arguments automatically deduced.
22
23#include <type_traits>
24#include <utility>
25
26#include <basis/seadNew.h>
27
28namespace sead
29{
30class Heap;
31
32/// Interface of a delegate for a member function with no argument.
33class IDelegate
34{
35public:
36 virtual void invoke() = 0;
37 virtual IDelegate* clone(Heap*) const { return nullptr; }
38 virtual bool isNoDummy() const { return true; }
39 void operator()() { return invoke(); }
40};
41
42/// @tparam R Return type
43template <typename R>
44class IDelegateR
45{
46public:
47 virtual R invoke() = 0;
48 virtual IDelegateR* clone(Heap*) const { return nullptr; }
49 virtual bool isNoDummy() const { return true; }
50 R operator()() { return invoke(); }
51};
52
53/// Interface of a delegate for a member function with one argument.
54/// @tparam A1 Type of the argument
55template <typename A1>
56class IDelegate1
57{
58public:
59 virtual void invoke(A1 a1) = 0;
60 virtual IDelegate1* clone(Heap*) const { return nullptr; }
61 virtual bool isNoDummy() const { return true; }
62 void operator()(A1 a1) { return invoke(a1); }
63};
64
65/// @tparam A1 Type of the argument
66/// @tparam R Return type
67template <typename A1, typename R>
68class IDelegate1R
69{
70public:
71 virtual R invoke(A1 a1) = 0;
72 virtual IDelegate1R* clone(Heap*) const { return nullptr; }
73 virtual bool isNoDummy() const { return true; }
74 R operator()(A1 a1) { return invoke(a1); }
75};
76
77/// Interface of a delegate for a member function with two arguments.
78/// @tparam A1 Type of the first argument
79/// @tparam A2 Type of the second argument
80template <typename A1, typename A2>
81class IDelegate2
82{
83public:
84 virtual void invoke(A1 a1, A2 a2) = 0;
85 virtual IDelegate2* clone(Heap*) const { return nullptr; }
86 virtual bool isNoDummy() const { return true; }
87 void operator()(A1 a1, A2 a2) { return invoke(a1, a2); }
88};
89
90/// @tparam A1 Type of the first argument
91/// @tparam A2 Type of the second argument
92/// @tparam R Return type
93template <typename A1, typename A2, typename R>
94class IDelegate2R
95{
96public:
97 virtual R invoke(A1 a1, A2 a2) = 0;
98 virtual IDelegate2R* clone(Heap*) const { return nullptr; }
99 virtual bool isNoDummy() const { return true; }
100 R operator()(A1 a1, A2 a2) { return invoke(a1, a2); }
101};
102
103/// Base class for delegate implementations.
104template <typename T, typename PTMF, typename Base>
105class DelegateBase : public Base
106{
107public:
108 DelegateBase() = default;
109 DelegateBase(T* instance, PTMF fn) : mInstance(instance), mFunctionPtr(fn) {}
110
111 T* instance() const { return mInstance; }
112 void setInstance(T* instance) { mInstance = instance; }
113 void setFunction(PTMF fn) { mFunctionPtr = fn; }
114
115 void bind(T* instance, PTMF fn)
116 {
117 setInstance(instance);
118 setFunction(fn);
119 }
120
121protected:
122 T* mInstance = nullptr;
123 PTMF mFunctionPtr = nullptr;
124};
125
126/// Partial specialization of DelegateBase for regular function pointers
127/// (*not* pointers-to-member-function).
128template <typename FunctionPointer, typename Base>
129class DelegateBase<void, FunctionPointer, Base> : public Base
130{
131public:
132 DelegateBase() = default;
133 explicit DelegateBase(FunctionPointer fn) : mFunctionPtr(fn) {}
134
135 void setFunction(FunctionPointer fn) { mFunctionPtr = fn; }
136
137protected:
138 FunctionPointer mFunctionPtr = nullptr;
139};
140
141/// Delegate for a member function with no argument.
142/// @tparam T Class type
143template <typename T>
144class Delegate : public DelegateBase<T, void (T::*)(), IDelegate>
145{
146public:
147 using Base = DelegateBase<T, void (T::*)(), IDelegate>;
148 using Base::Base;
149 void invoke() override { operator()(); }
150 void operator()() const
151 {
152 if (this->mInstance && this->mFunctionPtr)
153 return (this->mInstance->*(this->mFunctionPtr))();
154 }
155 Delegate* clone(Heap* heap) const override { return new (heap) Delegate(*this); }
156};
157
158/// @tparam T Class type
159/// @tparam R Return type
160template <typename T, typename R>
161class DelegateR : public DelegateBase<T, R (T::*)(), IDelegateR<R>>
162{
163public:
164 using Base = DelegateBase<T, R (T::*)(), IDelegateR<R>>;
165 using Base::Base;
166 R invoke() override { return operator()(); }
167 R operator()() const
168 {
169 if (this->mInstance && this->mFunctionPtr)
170 return (this->mInstance->*(this->mFunctionPtr))();
171 return {};
172 }
173 DelegateR* clone(Heap* heap) const override { return new (heap) DelegateR(*this); }
174};
175
176/// Delegate for a member function with one argument.
177/// @tparam T Class type
178/// @tparam A1 Type of the argument
179template <typename T, typename A1>
180class Delegate1 : public DelegateBase<T, void (T::*)(A1), IDelegate1<A1>>
181{
182public:
183 using Base = DelegateBase<T, void (T::*)(A1), IDelegate1<A1>>;
184 using Base::Base;
185 void invoke(A1 a1) override { operator()(a1); }
186 void operator()(A1 a1) const
187 {
188 if (this->mInstance && this->mFunctionPtr)
189 return (this->mInstance->*(this->mFunctionPtr))(a1);
190 }
191 Delegate1* clone(Heap* heap) const override { return new (heap) Delegate1(*this); }
192};
193
194/// @tparam T Class type
195/// @tparam A1 Type of the argument
196/// @tparam R Return type
197template <typename T, typename A1, typename R>
198class Delegate1R : public DelegateBase<T, R (T::*)(A1), IDelegate1R<A1, R>>
199{
200public:
201 using Base = DelegateBase<T, R (T::*)(A1), IDelegate1R<A1, R>>;
202 using Base::Base;
203 R invoke(A1 a1) override { return operator()(a1); }
204 R operator()(A1 a1) const
205 {
206 if (this->mInstance && this->mFunctionPtr)
207 return (this->mInstance->*(this->mFunctionPtr))(a1);
208 return {};
209 }
210 Delegate1R* clone(Heap* heap) const override { return new (heap) Delegate1R(*this); }
211};
212
213/// Delegate for a member function with two arguments.
214/// @tparam T Class type
215/// @tparam A1 Type of the first argument
216/// @tparam A2 Type of the second argument
217template <typename T, typename A1, typename A2>
218class Delegate2 : public DelegateBase<T, void (T::*)(A1, A2), IDelegate2<A1, A2>>
219{
220public:
221 using Base = DelegateBase<T, void (T::*)(A1, A2), IDelegate2<A1, A2>>;
222 using Base::Base;
223 void invoke(A1 a1, A2 a2) override { return operator()(a1, a2); }
224 void operator()(A1 a1, A2 a2) const
225 {
226 if (this->mInstance && this->mFunctionPtr)
227 return (this->mInstance->*(this->mFunctionPtr))(a1, a2);
228 }
229 Delegate2* clone(Heap* heap) const override { return new (heap) Delegate2(*this); }
230};
231
232/// @tparam T Class type
233/// @tparam A1 Type of the first argument
234/// @tparam A2 Type of the second argument
235/// @tparam R Return type
236template <typename T, typename A1, typename A2, typename R>
237class Delegate2R : public DelegateBase<T, R (T::*)(A1, A2), IDelegate2R<A1, A2, R>>
238{
239public:
240 using Base = DelegateBase<T, R (T::*)(A1, A2), IDelegate2R<A1, A2, R>>;
241 using Base::Base;
242 R invoke(A1 a1, A2 a2) override { return operator()(a1, a2); }
243 R operator()(A1 a1, A2 a2) const
244 {
245 if (this->mInstance && this->mFunctionPtr)
246 return (this->mInstance->*(this->mFunctionPtr))(a1, a2);
247 return {};
248 }
249 Delegate2R* clone(Heap* heap) const override { return new (heap) Delegate2R(*this); }
250};
251
252class DelegateFunc : public DelegateBase<void, void (*)(), IDelegate>
253{
254public:
255 using Base = DelegateBase<void, void (*)(), IDelegate>;
256 using Base::Base;
257 void invoke() override { operator()(); }
258 void operator()() const
259 {
260 if (this->mFunctionPtr)
261 return (*this->mFunctionPtr)();
262 }
263 DelegateFunc* clone(Heap* heap) const override { return new (heap) DelegateFunc(*this); }
264};
265
266template <typename R>
267class DelegateRFunc : public DelegateBase<void, R (*)(), IDelegateR<R>>
268{
269public:
270 using Base = DelegateBase<void, R (*)(), IDelegateR<R>>;
271 using Base::Base;
272 R invoke() override { return operator()(); }
273 R operator()() const
274 {
275 if (this->mFunctionPtr)
276 return (*this->mFunctionPtr)();
277 return {};
278 }
279 DelegateRFunc* clone(Heap* heap) const override { return new (heap) DelegateRFunc(*this); }
280};
281
282template <typename A1>
283class Delegate1Func : public DelegateBase<void, void (*)(A1), IDelegate1<A1>>
284{
285public:
286 using Base = DelegateBase<void, void (*)(A1), IDelegate1<A1>>;
287 using Base::Base;
288 void invoke(A1 a1) override { operator()(a1); }
289 void operator()(A1 a1) const
290 {
291 if (this->mFunctionPtr)
292 return (*this->mFunctionPtr)(a1);
293 }
294 Delegate1Func* clone(Heap* heap) const override { return new (heap) Delegate1Func(*this); }
295};
296
297template <typename A1, typename R>
298class Delegate1RFunc : public DelegateBase<void, R (*)(A1), IDelegate1R<A1, R>>
299{
300public:
301 using Base = DelegateBase<void, R (*)(A1), IDelegate1R<A1, R>>;
302 using Base::Base;
303 R invoke(A1 a1) override { return operator()(a1); }
304 R operator()(A1 a1) const
305 {
306 if (this->mFunctionPtr)
307 return (*this->mFunctionPtr)(a1);
308 return {};
309 }
310 Delegate1RFunc* clone(Heap* heap) const override { return new (heap) Delegate1RFunc(*this); }
311};
312
313template <typename A1, typename A2>
314class Delegate2Func : public DelegateBase<void, void (*)(A1, A2), IDelegate2<A1, A2>>
315{
316public:
317 using Base = DelegateBase<void, void (*)(A1, A2), IDelegate2<A1, A2>>;
318 using Base::Base;
319 void invoke(A1 a1, A2 a2) override { return operator()(a1, a2); }
320 void operator()(A1 a1, A2 a2) const
321 {
322 if (this->mFunctionPtr)
323 return (*this->mFunctionPtr)(a1, a2);
324 }
325 Delegate2Func* clone(Heap* heap) const override { return new (heap) Delegate2Func(*this); }
326};
327
328template <typename A1, typename A2, typename R>
329class Delegate2RFunc : public DelegateBase<void, R (*)(A1, A2), IDelegate2R<A1, A2, R>>
330{
331public:
332 using Base = DelegateBase<void, R (*)(A1, A2), IDelegate2R<A1, A2, R>>;
333 using Base::Base;
334 R invoke(A1 a1, A2 a2) override { return operator()(a1, a2); }
335 R operator()(A1 a1, A2 a2) const
336 {
337 if (this->mFunctionPtr)
338 return (*this->mFunctionPtr)(a1, a2);
339 return {};
340 }
341 Delegate2RFunc* clone(Heap* heap) const override { return new (heap) Delegate2RFunc(*this); }
342};
343
344template <typename Lambda>
345class LambdaDelegate : public IDelegate
346{
347public:
348 explicit LambdaDelegate(Lambda l) : mLambda(std::move(l)) {}
349 auto invoke() override { return mLambda(); }
350 auto operator()() const { return mLambda(); }
351 auto clone(Heap* heap) const override { return new (heap) LambdaDelegate(*this); }
352
353protected:
354 Lambda mLambda;
355};
356
357template <typename Lambda, typename R>
358class LambdaDelegateR : public IDelegateR<R>
359{
360public:
361 explicit LambdaDelegateR(Lambda l) : mLambda(std::move(l)) {}
362 auto invoke() override { return mLambda(); }
363 auto operator()() const { return mLambda(); }
364 auto clone(Heap* heap) const override { return new (heap) LambdaDelegateR(*this); }
365
366protected:
367 Lambda mLambda;
368};
369
370template <typename Lambda, typename A1>
371class LambdaDelegate1 : public IDelegate1<A1>
372{
373public:
374 explicit LambdaDelegate1(Lambda l) : mLambda(std::move(l)) {}
375 auto invoke(A1 a1) override { return mLambda(a1); }
376 auto operator()(A1 a1) const { return mLambda(a1); }
377 auto clone(Heap* heap) const override { return new (heap) LambdaDelegate1(*this); }
378
379protected:
380 Lambda mLambda;
381};
382
383template <typename Lambda, typename A1, typename R>
384class LambdaDelegate1R : public IDelegate1R<A1, R>
385{
386public:
387 explicit LambdaDelegate1R(Lambda l) : mLambda(std::move(l)) {}
388 auto invoke(A1 a1) override { return mLambda(a1); }
389 auto operator()(A1 a1) const { return mLambda(a1); }
390 auto clone(Heap* heap) const override { return new (heap) LambdaDelegate1R(*this); }
391
392protected:
393 Lambda mLambda;
394};
395
396template <typename Lambda, typename A1, typename A2>
397class LambdaDelegate2 : public IDelegate2<A1, A2>
398{
399public:
400 explicit LambdaDelegate2(Lambda l) : mLambda(std::move(l)) {}
401 auto invoke(A1 a1, A2 a2) override { return mLambda(a1, a2); }
402 auto operator()(A1 a1, A2 a2) const { return mLambda(a1, a2); }
403 auto clone(Heap* heap) const override { return new (heap) LambdaDelegate2(*this); }
404
405protected:
406 Lambda mLambda;
407};
408
409template <typename Lambda, typename A1, typename A2, typename R>
410class LambdaDelegate2R : public IDelegate2R<A1, A2, R>
411{
412public:
413 explicit LambdaDelegate2R(Lambda l) : mLambda(std::move(l)) {}
414 auto invoke(A1 a1, A2 a2) override { return mLambda(a1, a2); }
415 auto operator()(A1 a1, A2 a2) const { return mLambda(a1, a2); }
416 auto clone(Heap* heap) const override { return new (heap) LambdaDelegate2R(*this); }
417
418protected:
419 Lambda mLambda;
420};
421
422// To work around the lack of CTAD.
423template <typename Lambda>
424static auto makeLambdaDelegate(Lambda&& l)
425{
426 return LambdaDelegate<Lambda>(std::forward<Lambda>(l));
427}
428
429template <typename Lambda>
430static auto makeLambdaDelegateR(Lambda&& l)
431{
432#if __cplusplus < 202002L
433 using R = std::result_of_t<Lambda()>;
434#else
435 using R = std::invoke_result_t<Lambda>;
436#endif
437 return LambdaDelegateR<Lambda, R>(std::forward<Lambda>(l));
438}
439
440template <typename A1, typename Lambda>
441static auto makeLambdaDelegate1(Lambda&& l)
442{
443 return LambdaDelegate1<Lambda, A1>(std::forward<Lambda>(l));
444}
445
446template <typename A1, typename Lambda>
447static auto makeLambdaDelegate1R(Lambda&& l)
448{
449#if __cplusplus < 202002L
450 using R = std::result_of_t<Lambda(A1)>;
451#else
452 using R = std::invoke_result_t<Lambda, A1>;
453#endif
454 return LambdaDelegate1R<Lambda, A1, R>(std::forward<Lambda>(l));
455}
456
457template <typename A1, typename A2, typename Lambda>
458static auto makeLambdaDelegate2(Lambda&& l)
459{
460 return LambdaDelegate2<Lambda, A1, A2>(std::forward<Lambda>(l));
461}
462
463template <typename A1, typename A2, typename Lambda>
464static auto makeLambdaDelegate2R(Lambda&& l)
465{
466#if __cplusplus < 202002L
467 using R = std::result_of_t<Lambda(A1, A2)>;
468#else
469 using R = std::invoke_result_t<Lambda, A1, A2>;
470#endif
471 return LambdaDelegate2R<Lambda, A1, A2, R>(std::forward<Lambda>(l));
472}
473
474namespace detail
475{
476class DummyClassForDelegate
477{
478};
479
480template <typename Interface, typename AnyClass, size_t StorageSize>
481class AnyDelegateImpl
482{
483public:
484 /// Stores a dummy function.
485 AnyDelegateImpl() { new (&mStorage) typename AnyClass::UnbindDummy(); }
486
487 /// Stores a function.
488 template <typename DelegateType>
489 AnyDelegateImpl(DelegateType other)
490 {
491 *this = std::move(other);
492 }
493
494 /// Stores a function.
495 template <typename DelegateType>
496 AnyDelegateImpl& operator=(DelegateType other)
497 {
498 static_assert(std::is_trivially_destructible<DelegateType>());
499 static_assert(std::is_base_of<Interface, DelegateType>());
500 static_assert(sizeof(DelegateType) <= sizeof(mStorage));
501 new (&mStorage) DelegateType(std::move(other));
502 return *this;
503 }
504
505 /// Calls the stored function.
506 template <typename... Args>
507 auto operator()(Args&&... args)
508 {
509 return getDelegate()->invoke(std::forward<Args>(args)...);
510 }
511
512 /// Calls the stored function.
513 template <typename... Args>
514 auto operator()(Args&&... args) const
515 {
516 return getDelegate()->invoke(std::forward<Args>(args)...);
517 }
518
519 /// Checks if a non-dummy function is stored.
520 explicit operator bool() const { return getDelegate()->isNoDummy(); }
521
522 Interface* getDelegate() { return reinterpret_cast<Interface*>(&mStorage); }
523 const Interface* getDelegate() const { return reinterpret_cast<const Interface*>(&mStorage); }
524
525protected:
526 using Interface_ = Interface;
527 std::aligned_storage_t<StorageSize, alignof(Interface)> mStorage;
528};
529} // namespace detail
530
531/// A type-erased delegate that can store either a Delegate or a LambdaDelegate
532/// without heap allocations.
533class AnyDelegate : public detail::AnyDelegateImpl<IDelegate, AnyDelegate,
534 sizeof(Delegate<detail::DummyClassForDelegate>)>
535{
536public:
537 using Base = AnyDelegateImpl;
538
539 class UnbindDummy final : public Base::Interface_
540 {
541 public:
542 void invoke() override {}
543 bool isNoDummy() const override { return false; }
544 };
545 using Base::Base;
546 using Base::operator=;
547};
548
549template <typename R>
550class AnyDelegateR
551 : public detail::AnyDelegateImpl<IDelegateR<R>, AnyDelegateR<R>,
552 sizeof(DelegateR<detail::DummyClassForDelegate, R>)>
553{
554public:
555 using Base = detail::AnyDelegateImpl<IDelegateR<R>, AnyDelegateR<R>,
556 sizeof(DelegateR<detail::DummyClassForDelegate, R>)>;
557
558 class UnbindDummy final : public Base::Interface_
559 {
560 public:
561 R invoke() override { return {}; }
562 bool isNoDummy() const override { return false; }
563 };
564 using Base::Base;
565 using Base::operator=;
566};
567
568template <typename A1>
569class AnyDelegate1
570 : public detail::AnyDelegateImpl<IDelegate1<A1>, AnyDelegate1<A1>,
571 sizeof(Delegate1<detail::DummyClassForDelegate, A1>)>
572{
573public:
574 using Base = detail::AnyDelegateImpl<IDelegate1<A1>, AnyDelegate1<A1>,
575 sizeof(Delegate1<detail::DummyClassForDelegate, A1>)>;
576
577 class UnbindDummy final : public Base::Interface_
578 {
579 public:
580 void invoke(A1) override {}
581 bool isNoDummy() const override { return false; }
582 };
583 using Base::Base;
584 using Base::operator=;
585};
586
587template <typename A1, typename R>
588class AnyDelegate1R
589 : public detail::AnyDelegateImpl<IDelegate1R<A1, R>, AnyDelegate1R<A1, R>,
590 sizeof(Delegate1R<detail::DummyClassForDelegate, A1, R>)>
591{
592public:
593 using Base = detail::AnyDelegateImpl<IDelegate1R<A1, R>, AnyDelegate1R<A1, R>,
594 sizeof(Delegate1R<detail::DummyClassForDelegate, A1, R>)>;
595
596 class UnbindDummy final : public Base::Interface_
597 {
598 public:
599 R invoke(A1) override { return {}; }
600 bool isNoDummy() const override { return false; }
601 };
602 using Base::Base;
603 using Base::operator=;
604};
605
606template <typename A1, typename A2>
607class AnyDelegate2
608 : public detail::AnyDelegateImpl<IDelegate2<A1, A2>, AnyDelegate2<A1, A2>,
609 sizeof(Delegate2<detail::DummyClassForDelegate, A1, A2>)>
610{
611public:
612 using Base = detail::AnyDelegateImpl<IDelegate2<A1, A2>, AnyDelegate2<A1, A2>,
613 sizeof(Delegate2<detail::DummyClassForDelegate, A1, A2>)>;
614
615 class UnbindDummy final : public Base::Interface_
616 {
617 public:
618 void invoke(A1, A2) override {}
619 bool isNoDummy() const override { return false; }
620 };
621 using Base::Base;
622 using Base::operator=;
623};
624
625template <typename A1, typename A2, typename R>
626class AnyDelegate2R
627 : public detail::AnyDelegateImpl<IDelegate2R<A1, A2, R>, AnyDelegate2R<A1, A2, R>,
628 sizeof(Delegate2R<detail::DummyClassForDelegate, A1, A2, R>)>
629{
630public:
631 using Base =
632 detail::AnyDelegateImpl<IDelegate2R<A1, A2, R>, AnyDelegate2R<A1, A2, R>,
633 sizeof(Delegate2R<detail::DummyClassForDelegate, A1, A2, R>)>;
634
635 class UnbindDummy final : public Base::Interface_
636 {
637 public:
638 R invoke(A1, A2) override { return {}; }
639 bool isNoDummy() const override { return false; }
640 };
641 using Base::Base;
642 using Base::operator=;
643};
644} // namespace sead
645