载入中...
搜索中...
未找到
CapabilityOwned.h
浏览该文件的文档.
1#pragma once
2
13#include "common/Capability.h"
14#include "common/Diagnostic.h"
15#include "common/Export.h"
16#include "common/Result.h"
17#include "common/Status.h"
18
19#include <cstdint>
20#include <memory>
21#include <mutex>
22#include <string>
23#include <string_view>
24#include <unordered_map>
25#include <utility>
26
27namespace eve::cap {
28
36 std::string id;
37 std::uint64_t generation = 0;
38
39 [[nodiscard]] friend bool operator==(const OwnedProviderHandle&, const OwnedProviderHandle&) = default;
40};
41
49template <class I>
51public:
52 OwnedProviderLease() = default;
53
54 [[nodiscard]] const OwnedProviderHandle& handle() const noexcept { return handle_; }
55 [[nodiscard]] explicit operator bool() const noexcept { return static_cast<bool>(provider_); }
57 [[nodiscard]] I* get() const noexcept { return provider_.get(); }
58 [[nodiscard]] I& operator*() const noexcept { return *provider_; }
59 [[nodiscard]] I* operator->() const noexcept { return provider_.get(); }
60
61private:
62 template <class>
64
65 OwnedProviderLease(OwnedProviderHandle handle, std::shared_ptr<I> provider)
66 : handle_(std::move(handle)), provider_(std::move(provider)) {}
67
68 OwnedProviderHandle handle_;
69 std::shared_ptr<I> provider_;
70};
71
72namespace detail {
73
74struct OwnedEntryBase {
75 virtual ~OwnedEntryBase() = default;
81 virtual void* raw() noexcept = 0;
87 virtual std::shared_ptr<void> shared() const noexcept = 0;
88};
89
90template <class I>
91struct OwnedEntry final : OwnedEntryBase {
92 explicit OwnedEntry(std::shared_ptr<I> provider) : provider(std::move(provider)) {}
98 void* raw() noexcept override { return provider.get(); }
104 std::shared_ptr<void> shared() const noexcept override { return provider; }
105 std::shared_ptr<I> provider;
106};
107
108struct OwnedSlot {
109 OwnedProviderHandle handle;
110 std::unique_ptr<OwnedEntryBase> entry;
111};
112
114EVENGINE_API_FOUNDATION std::unordered_map<std::string, OwnedSlot>& ownedSlots(const char* capabilityName);
115EVENGINE_API_FOUNDATION std::unordered_map<std::string, std::uint64_t>& ownedGenerations(const char* capabilityName);
117
118} // namespace detail
119
125template <class I>
127public:
134 [[nodiscard]] static Result<OwnedProviderHandle> provide(std::string id, std::shared_ptr<I> provider) {
135 if (id.empty() || !provider) {
136 return Result<OwnedProviderHandle>::failure(Diagnostic::error(
137 DiagnosticCode::InvalidArgument, "owned capability requires id and implementation", "id"));
138 }
139 std::scoped_lock lock(detail::ownedMutex());
140 auto& slots = detail::ownedSlots(I::capabilityName);
141 if (slots.contains(id)) {
142 return Result<OwnedProviderHandle>::failure(Diagnostic::error(
143 DiagnosticCode::Conflict, "owned capability id is already published", "id"));
144 }
145 auto& generations = detail::ownedGenerations(I::capabilityName);
147 auto [it, inserted] =
148 slots.emplace(std::move(id), detail::OwnedSlot{handle, std::make_unique<detail::OwnedEntry<I>>(
149 std::move(provider))});
150 (void)inserted;
151 // Also expose the current generation through the borrowed single-provider slot so
152 // existing `query` / `ProviderRef` consumers see the same instance.
153 detail::provideRaw(I::capabilityName, it->second.entry->raw());
154 return Result<OwnedProviderHandle>::success(std::move(handle), Status::success(StatusCode::Applied));
155 }
156
162 std::scoped_lock lock(detail::ownedMutex());
163 auto& slots = detail::ownedSlots(I::capabilityName);
164 const auto found = slots.find(handle.id);
165 if (found == slots.end()) {
166 const auto& generations = detail::ownedGenerations(I::capabilityName);
167 const bool seen = generations.contains(handle.id);
168 return Result<OwnedProviderLease<I>>::failure(Diagnostic::error(
169 seen ? DiagnosticCode::Conflict : DiagnosticCode::Unsupported,
170 seen ? "owned capability handle is stale" : "owned capability provider is not available", "handle"));
171 }
172 if (found->second.handle != handle) {
173 return Result<OwnedProviderLease<I>>::failure(
174 Diagnostic::error(DiagnosticCode::Conflict, "owned capability handle is stale", "handle"));
175 }
176 auto typed = std::static_pointer_cast<I>(found->second.entry->shared());
177 return Result<OwnedProviderLease<I>>::success(OwnedProviderLease<I>(handle, std::move(typed)),
178 Status::success(StatusCode::Applied));
179 }
180
184 [[nodiscard]] static Result<OwnedProviderLease<I>> acquire(std::string_view id) {
185 std::scoped_lock lock(detail::ownedMutex());
186 auto& slots = detail::ownedSlots(I::capabilityName);
187 const auto found = slots.find(std::string(id));
188 if (found == slots.end()) {
189 return Result<OwnedProviderLease<I>>::failure(Diagnostic::error(
190 DiagnosticCode::Unsupported, "owned capability provider is not available", "id"));
191 }
192 auto typed = std::static_pointer_cast<I>(found->second.entry->shared());
193 return Result<OwnedProviderLease<I>>::success(
194 OwnedProviderLease<I>(found->second.handle, std::move(typed)), Status::success(StatusCode::Applied));
195 }
196
200 [[nodiscard]] static Result<void> unload(const OwnedProviderHandle& handle) {
201 std::shared_ptr<void> keepAlive;
202 {
203 std::scoped_lock lock(detail::ownedMutex());
204 auto& slots = detail::ownedSlots(I::capabilityName);
205 const auto found = slots.find(handle.id);
206 if (found == slots.end() || found->second.handle != handle) {
208 Diagnostic::error(DiagnosticCode::Conflict, "owned capability handle is stale", "handle"));
209 }
210 // Use auto (not void*) so the local is not linted as a public pointer API.
211 const auto borrowed = found->second.entry->raw();
212 keepAlive = found->second.entry->shared();
213 slots.erase(found);
214 detail::revokeRaw(I::capabilityName, borrowed);
215 }
216 (void)keepAlive;
217 return Result<void>::success(Status::success(StatusCode::Applied));
218 }
219};
220
221} // namespace eve::cap
std::unordered_map< std::string, std::unordered_map< std::string, std::uint64_t > > generations
Stable, structured diagnostics shared by engine modules.
#define EVENGINE_API_FOUNDATION
每个链接组(link group)各自的导出宏。
Definition Export.h:106
const RuntimeTensor * borrowed
std::string id
Definition PlayHost.cpp:108
PrimitiveHandle handle
int detail
Move-only, checked operation results for the common layer.
bool found
LocalPageCacheEntry slots[ShadowConfig::kLocalSlots]
Structured operation status used by the common Result foundation.
Move-only operation result carrying either a value or Status.
Definition Result.h:155
Owning lease that keeps a shared_ptr provider alive while borrowed.
I * get() const noexcept
Borrowed interface pointer valid while this lease remains alive.
I * operator->() const noexcept
const OwnedProviderHandle & handle() const noexcept
I & operator*() const noexcept
Thread-safe owned-provider table keyed by capability name + provider id.
static Result< void > unload(const OwnedProviderHandle &handle)
Unpublish one exact provider generation and clear the borrowed slot when it matches.
static Result< OwnedProviderLease< I > > acquire(std::string_view id)
Acquire the current generation published under id.
static Result< OwnedProviderLease< I > > acquire(const OwnedProviderHandle &handle)
Acquire an owning lease for an exact handle generation.
static Result< OwnedProviderHandle > provide(std::string id, std::shared_ptr< I > provider)
Publish an owning provider under id, replacing only after explicit unload.
std::unordered_map< std::string, OwnedSlot > & ownedSlots(const char *capabilityName)
std::mutex & ownedMutex()
std::unordered_map< std::string, std::uint64_t > & ownedGenerations(const char *capabilityName)
Generation-qualified id for one owned capability provider.
friend bool operator==(const OwnedProviderHandle &, const OwnedProviderHandle &)=default