载入中...
搜索中...
未找到
Capability.h
浏览该文件的文档.
1#pragma once
2
3// Capability registry: how one module uses another without depending on it.
4//
5// Modules normally reach each other by including the provider's header and
6// calling it directly, which welds the two together at link time. That is fine
7// downwards (map may depend on graphics) but not upwards: it is why filesystem
8// ends up knowing about particles and why the SDL event pump knows about every
9// input module. Those upward edges are what stop a module from being trimmed
10// out of a build.
11//
12// A capability inverts that. The interface lives with the *consumer* (or in
13// common/), the provider registers an implementation at startup, and the
14// consumer queries it and copes with nullptr. Neither side includes the other.
15// common/RenderTrace.h has worked this way for the render tracer; this
16// generalises the same idea.
17//
18// Declaring an interface -- give it a stable name so the key survives the
19// module being compiled into a plugin:
20//
21// class IGpuInfo {
22// public:
23// static constexpr const char* capabilityName = "IGpuInfo";
24// virtual ~IGpuInfo() = default;
25// virtual std::string gpuName() const = 0;
26// };
27//
28// One provider (a service):
29//
30// eve::cap::provide<IGpuInfo>(&myImpl); // provider side
31// if (auto* g = eve::cap::query<IGpuInfo>()) // consumer side
32// name = g->gpuName();
33//
34// Many providers (handlers / listeners), dispatched in priority order,
35// lower value first:
36//
37// eve::cap::addListener<IHotReloadHandler>(&h, 10);
38// eve::cap::forEach<IHotReloadHandler>([&](IHotReloadHandler* h) { ... });
39//
40// Lifetime is the caller's: whatever is registered must outlive the registry
41// entry, or be withdrawn with revoke() / removeListener() first. Registration
42// is not thread-safe and is expected to happen during module construction;
43// query() and forEach() are safe to call concurrently once registration has
44// settled.
45
46#include "common/Export.h"
47
48#include <cstddef>
49#include <utility>
50
51namespace eve::cap {
52
53namespace detail {
54
55EVENGINE_API void provideRaw(const char* name, void* impl);
56EVENGINE_API void* queryRaw(const char* name);
57EVENGINE_API void revokeRaw(const char* name, void* impl);
58
59EVENGINE_API void addListenerRaw(const char* name, void* impl, int priority);
60EVENGINE_API void removeListenerRaw(const char* name, void* impl);
61EVENGINE_API size_t listenerCountRaw(const char* name);
62EVENGINE_API void* listenerAtRaw(const char* name, size_t index);
63
66
67} // namespace detail
68
70template <class I>
71void provide(I* impl) {
72 detail::provideRaw(I::capabilityName, impl);
73}
74
76template <class I>
77I* query() {
78 return static_cast<I*>(detail::queryRaw(I::capabilityName));
79}
80
82template <class I>
83void revoke(I* impl) {
84 detail::revokeRaw(I::capabilityName, impl);
85}
86
88template <class I>
89void addListener(I* impl, int priority = 0) {
90 detail::addListenerRaw(I::capabilityName, impl, priority);
91}
92
93template <class I>
95 detail::removeListenerRaw(I::capabilityName, impl);
96}
97
98template <class I>
99size_t listenerCount() {
100 return detail::listenerCountRaw(I::capabilityName);
101}
102
103template <class I>
104I* listenerAt(size_t index) {
105 return static_cast<I*>(detail::listenerAtRaw(I::capabilityName, index));
106}
107
113template <class I, class F>
114void forEach(F&& fn) {
115 const size_t n = detail::listenerCountRaw(I::capabilityName);
116 for (size_t i = 0; i < n; ++i)
117 if (auto* impl = static_cast<I*>(detail::listenerAtRaw(I::capabilityName, i)))
118 fn(impl);
119}
120
125template <class I, class F>
127 const size_t n = detail::listenerCountRaw(I::capabilityName);
128 for (size_t i = 0; i < n; ++i) {
129 auto* impl = static_cast<I*>(detail::listenerAtRaw(I::capabilityName, i));
130 if (impl && fn(impl)) return true;
131 }
132 return false;
133}
134
135} // namespace eve::cap
int priority
void * impl
#define EVENGINE_API
宿主(eve / libmain)导出宏;插件从进程导入同一批符号。
Definition Export.h:16
glm::vec3 n
Definition Grass.cpp:64
const char * name
Definition RockMesh.cpp:21
SettlementPipeline::Stage fn
void addListenerRaw(const char *name, void *impl, int priority)
void provideRaw(const char *name, void *impl)
void * queryRaw(const char *name)
void * listenerAtRaw(const char *name, size_t index)
void revokeRaw(const char *name, void *impl)
size_t listenerCountRaw(const char *name)
void removeListenerRaw(const char *name, void *impl)
void revoke(I *impl)
Definition Capability.h:83
I * query()
Definition Capability.h:77
void provide(I *impl)
Definition Capability.h:71
void removeListener(I *impl)
Definition Capability.h:94
size_t listenerCount()
Definition Capability.h:99
bool forEachUntil(F &&fn)
Definition Capability.h:126
void addListener(I *impl, int priority=0)
Definition Capability.h:89
I * listenerAt(size_t index)
Definition Capability.h:104
void forEach(F &&fn)
Definition Capability.h:114