1313// (which shouldn't happen, since the point of this is to avoid the heap,
1414// but it could...)
1515
16- template<unsigned BUFFER_SIZE = 2 * sizeof(void *)>
17- class CallbackSized {
18- private:
19- // static constexpr unsigned BUFFER_SIZE = 2 * sizeof(void *);
20-
21- public:
22- CallbackSized() = default;
23-
24- template<typename Callable>
25- CallbackSized(Callable callable) {
26- static_assert(sizeof(Callable) <= BUFFER_SIZE);
27- static_assert(std::is_invocable_v<Callable>);
28-
29- new (&m_data[0]) Callable(callable);
30- m_callback = invoke<Callable>;
31- m_destroy = destroy<Callable>;
32- }
33-
34- ~CallbackSized() {
35- if (m_destroy)
36- m_destroy(&m_data[0]);
37- }
38-
39- void call() {
40- // if (m_callback)
41- m_callback(&m_data[0]);
42- return;
43- }
44-
45- void operator()() {
46- call();
47- }
48-
49- operator bool() {
50- return m_callback;
51- }
52-
53- private:
54- template<typename Callable>
55- static void invoke(void *object) {
56- Callable &callable = *reinterpret_cast<Callable *>(object);
57- callable();
58- }
59-
60- template<typename Callable>
61- static void destroy(void *object) {
62- Callable &callable = *reinterpret_cast<Callable *>(object);
63- callable.~Callable();
64- }
65-
66- private:
67- using CallbackM = void (*)(void *);
68- CallbackM m_callback{};
69-
70- using Deleter = void (*)(void *);
71- Deleter m_destroy{};
72-
73- alignas(uint64_t) uint8_t m_data[BUFFER_SIZE];
74- };
75-
76- using Callback = CallbackSized<2 * sizeof(void *)>;
77-
7816// Function<T> is a callback that takes parameters and returns something
79- template<typename Signature>
80- struct Function {};
81-
82- template<typename Ret, typename... Args>
83- class Function<Ret(Args...)> {
84- private:
85- static constexpr uint8_t BUFFER_SIZE = 2 * sizeof(void *);
17+ template<unsigned buffer_size, typename Signature>
18+ struct FunctionSized {};
8619
20+ template<unsigned buffer_size, typename Ret, typename... Args>
21+ class FunctionSized<buffer_size, Ret(Args...)> {
8722public:
88- Function () = default;
23+ FunctionSized () = default;
8924
9025 template<typename Callable>
91- Function( Callable callable) {
92- static_assert(sizeof( Callable) <= BUFFER_SIZE);
93- static_assert(std::is_invocable_v <Callable, Args...>);
94-
26+ requires(sizeof( Callable) <= buffer_size && std::is_invocable_v<Callable, Args...>)
27+ FunctionSized( Callable callable)
28+ : m_callback{invoke <Callable>}
29+ , m_destroy{destroy<Callable>} {
9530 new (&m_data[0]) Callable(callable);
96- m_callback = invoke<Callable>;
97- m_destroy = destroy<Callable>;
9831 }
9932
100- ~Function () {
33+ ~FunctionSized () {
10134 if (m_destroy)
10235 m_destroy(&m_data[0]);
10336 }
10437
10538 Ret call(Args... args) {
106- if (m_callback)
107- return m_callback(&m_data[0], std::forward<Args>(args)...);
108- return Ret();
39+ return m_callback(&m_data[0], std::forward<Args>(args)...);
10940 }
11041
11142 Ret operator()(Args... args) {
11243 return call(std::forward<Args>(args)...);
11344 }
11445
46+ operator bool() const {
47+ return m_callback;
48+ }
49+
11550private:
11651 template<typename Callable>
11752 static Ret invoke(void *object, Args... args) {
11853 Callable &callable = *reinterpret_cast<Callable *>(object);
119- return callable(std::forward<Args>(args)...);
54+ if constexpr (std::is_same_v<void, Ret>)
55+ callable(std::forward<Args>(args)...);
56+ else
57+ return callable(std::forward<Args>(args)...);
12058 }
12159
12260 template<typename Callable>
@@ -132,5 +70,13 @@ private:
13270 using Deleter = void (*)(void *);
13371 Deleter m_destroy{};
13472
135- alignas(uint64_t) uint8_t m_data[BUFFER_SIZE ];
73+ alignas(uint64_t) uint8_t m_data[buffer_size ];
13674};
75+
76+ template<typename Signature>
77+ using Function = FunctionSized<sizeof(void *) * 2, Signature>;
78+
79+ template<unsigned size = sizeof(void *) * 2>
80+ using CallbackSized = FunctionSized<size, void(void)>;
81+
82+ using Callback = CallbackSized<2 * sizeof(void *)>;
0 commit comments