-
Notifications
You must be signed in to change notification settings - Fork 50
/
callback.hpp
131 lines (122 loc) · 3.85 KB
/
callback.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#pragma once
#include <cib/builder_meta.hpp>
#include <stdx/compiler.hpp>
#include <stdx/panic.hpp>
#include <array>
#include <concepts>
#include <cstddef>
#include <utility>
namespace callback {
/**
* Builder for simple callbacks.
*
* Components can add their own callback function to this builder to be
* executed when the service is executed with the same function arguments.
*
* @tparam NumFuncs
* The number of functions currently registered with this builder.
*
* @tparam ArgTypes
* List of argument types that must be passed into the callback when it is
* invoked.
*
* @see callback::service
*/
template <int NumFuncs = 0, typename... ArgTypes> struct builder {
using func_ptr_t = void (*)(ArgTypes...);
std::array<func_ptr_t, NumFuncs> funcs{};
/**
* Add a function to be executed when the callback service is invoked.
*
* Do not call this function directly. The library will add functions
* to service builders based on a project's cib::config and cib::extend
* declarations.
*
* @return
* A version of this callback builder with the addition of func.
*
* @see cib::extend
* @see cib::nexus
*/
template <std::convertible_to<func_ptr_t>... Fs>
[[nodiscard]] constexpr auto add(Fs &&...fs) const {
builder<NumFuncs + sizeof...(Fs), ArgTypes...> cb;
auto i = std::size_t{};
while (i < NumFuncs) {
cb.funcs[i] = funcs[i];
++i;
}
((cb.funcs[i++] = std::forward<Fs>(fs)), ...);
return cb;
}
/**
* Build and return a function pointer to the implemented callback
* builder. Used by cib nexus to automatically build an initialized
* builder.
*
* Do not call directly.
*
* @tparam BuilderValue
* Struct that contains a "static constexpr auto value" field with the
* initialized builder.
*
* @return
* Function pointer to the implemented callback service.
*/
template <typename BuilderValue>
[[nodiscard]] CONSTEVAL static auto build() {
return run<BuilderValue>;
}
private:
/**
* Runtime implementation of a callback service.
*
* Calls each registered function in an undefined order. The order
* functions are called should not be depended upon and could
* change from one release to the next.
*
* This function will be available from nexus::builder<...> or
* cib::built<...>.
*
* @tparam BuilderValue
* A type that contains a constexpr static value field with the
* fully initialized callback builder.
*
* @param args
* The arguments to be passed to every registered function.
*
* @see cib::nexus
* @see cib::built
*/
template <typename BuilderValue> static void run(ArgTypes... args) {
constexpr auto handler_builder = BuilderValue::value;
[&]<std::size_t... Is>(std::index_sequence<Is...>) {
(handler_builder.funcs[Is](args...), ...);
}(std::make_index_sequence<NumFuncs>{});
}
};
/**
* Extend this to create named callback services.
*
* Types that extend service can be used as unique names with
* cib::exports and cib::extend.
*
* @tparam ArgTypes
* The function arguments that must be passed into the callback
* services implementation. any_t function registered with this
* callback service must also have a compatible signature.
*
* @see cib::exports
* @see cib::extend
*/
template <typename... ArgTypes> struct service {
using builder_t = builder<0, ArgTypes...>;
using interface_t = void (*)(ArgTypes...);
CONSTEVAL static auto uninitialized() -> interface_t {
return [](ArgTypes...) {
stdx::panic<
"Attempting to run callback before it is initialized">();
};
}
};
} // namespace callback