载入中...
搜索中...
未找到
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 <vector>
50
51namespace eve::cap {
52
53namespace detail {
54
56EVENGINE_API_FOUNDATION void provideRaw(const char* name, void* impl);
58EVENGINE_API_FOUNDATION void* queryRaw(const char* name);
60EVENGINE_API_FOUNDATION void revokeRaw(const char* name, void* impl);
61
63EVENGINE_API_FOUNDATION void addListenerRaw(const char* name, void* impl, int priority);
65EVENGINE_API_FOUNDATION void removeListenerRaw(const char* name, void* impl);
69EVENGINE_API_FOUNDATION void* listenerAtRaw(const char* name, size_t index);
70
74
75} // namespace detail
76
78template <class I>
80void provide(I* impl) {
82 detail::provideRaw(I::capabilityName, impl);
83}
84
86template <class I>
88I* query() {
89 return static_cast<I*>(detail::queryRaw(I::capabilityName));
90}
91
106template <class I>
108public:
109 ProviderRef() = default;
111 explicit ProviderRef(I* impl) noexcept : ptr_(impl) {}
112
113 ProviderRef(const ProviderRef&) = delete;
115 ProviderRef(ProviderRef&& other) noexcept : ptr_(other.ptr_) { other.ptr_ = nullptr; }
116 ProviderRef& operator=(ProviderRef&& other) noexcept {
117 if (this != &other) {
118 ptr_ = other.ptr_;
119 other.ptr_ = nullptr;
120 }
121 return *this;
122 }
123
128 [[nodiscard]] static ProviderRef bind() { return ProviderRef(query<I>()); }
129
131 [[nodiscard]] I* get() const noexcept { return ptr_; }
132 [[nodiscard]] explicit operator bool() const noexcept { return ptr_ != nullptr; }
133 [[nodiscard]] I& operator*() const noexcept { return *ptr_; }
134 [[nodiscard]] I* operator->() const noexcept { return ptr_; }
135
136private:
137 I* ptr_ = nullptr;
138};
139
141template <class I>
143void revoke(I* impl) {
145 detail::revokeRaw(I::capabilityName, impl);
146}
147
149template <class I>
151void addListener(I* impl, int priority = 0) {
153 detail::addListenerRaw(I::capabilityName, impl, priority);
154}
155
156template <class I>
160 detail::removeListenerRaw(I::capabilityName, impl);
161}
162
163template <class I>
167 return detail::listenerCountRaw(I::capabilityName);
168}
169
170template <class I>
172I* listenerAt(size_t index) {
173 return static_cast<I*>(detail::listenerAtRaw(I::capabilityName, index));
174}
175
184template <class I, class F>
186void forEach(F&& fn) {
187 const size_t n = detail::listenerCountRaw(I::capabilityName);
188 std::vector<I*> snapshot;
189 snapshot.reserve(n);
190 for (size_t i = 0; i < n; ++i) {
191 if (auto* impl = static_cast<I*>(detail::listenerAtRaw(I::capabilityName, i)))
192 snapshot.push_back(impl);
193 }
194 for (auto* impl : snapshot) fn(impl);
195}
196
203template <class I, class F>
205bool forEachUntil(F&& fn) {
206 const size_t n = detail::listenerCountRaw(I::capabilityName);
207 std::vector<I*> snapshot;
208 snapshot.reserve(n);
209 for (size_t i = 0; i < n; ++i) {
210 if (auto* impl = static_cast<I*>(detail::listenerAtRaw(I::capabilityName, i)))
211 snapshot.push_back(impl);
212 }
213 for (auto* impl : snapshot)
214 if (fn(impl)) return true;
215 return false;
216}
217
218} // namespace eve::cap
int priority
void * impl
#define EVENGINE_API_FOUNDATION
每个链接组(link group)各自的导出宏。
Definition Export.h:106
glm::vec3 n
Definition Grass.cpp:63
std::string name
int detail
uint32_t index
One-shot borrowed capability pointer for composition roots and hot paths.
Definition Capability.h:107
ProviderRef(I *impl) noexcept
Capture an already-resolved provider pointer (may be nullptr).
Definition Capability.h:111
static ProviderRef bind()
Resolve I once from the registry.
Definition Capability.h:128
I * operator->() const noexcept
Definition Capability.h:134
ProviderRef & operator=(ProviderRef &&other) noexcept
Definition Capability.h:116
I * get() const noexcept
Borrowed provider, or nullptr when unbound / absent at bind time.
Definition Capability.h:131
ProviderRef & operator=(const ProviderRef &)=delete
ProviderRef(const ProviderRef &)=delete
ProviderRef(ProviderRef &&other) noexcept
Definition Capability.h:115
I & operator*() const noexcept
Definition Capability.h:133
size_t listenerCountRaw(const char *name)
Listener count raw.
void addListenerRaw(const char *name, void *impl, int priority)
Adds listener raw.
void provideRaw(const char *name, void *impl)
Provides raw.
void removeListenerRaw(const char *name, void *impl)
Removes listener raw.
void * queryRaw(const char *name)
Queries raw.
void revokeRaw(const char *name, void *impl)
Revoke raw.
void clearAllRaw()
Clears all raw.
void * listenerAtRaw(const char *name, size_t index)
Listener at raw.
void revoke(I *impl)
Revoke.
Definition Capability.h:143
I * query()
Queries .
Definition Capability.h:88
void provide(I *impl)
Provides .
Definition Capability.h:80
void removeListener(I *impl)
Removes listener.
Definition Capability.h:158
size_t listenerCount()
Listener count.
Definition Capability.h:165
bool forEachUntil(F &&fn)
Call fn for each snapshotted implementation until one returns true.
Definition Capability.h:205
void addListener(I *impl, int priority=0)
Adds listener.
Definition Capability.h:151
I * listenerAt(size_t index)
Listener at.
Definition Capability.h:172
void forEach(F &&fn)
Call fn for every implementation of I in priority order.
Definition Capability.h:186
SettlementPipeline::Stage fn