MayaFlux 0.1.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
BackendRegistry.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <typeindex>
4
5namespace MayaFlux::Registry {
6
7/**
8 * @brief Thread-safe singleton registry for backend service discovery
9 *
10 * Provides centralized, type-safe registry for backend capabilities without
11 * creating dependencies between processing components and specific backend
12 * implementations. Backends register their services on initialization, and
13 * processing components (Buffers, Nodes, Coroutines, etc.) query for needed
14 * capabilities at runtime.
15 *
16 * Design Philosophy:
17 * - Zero coupling between consumers and backends
18 * - Runtime service discovery with compile-time type safety
19 * - Graceful degradation when services unavailable
20 * - Thread-safe for concurrent access across subsystems
21 * - Singleton to avoid engine/subsystem dependencies
22 * - Hot-swappable backends via re-registration
23 *
24 * Thread Safety:
25 * All methods are thread-safe. Registration and queries can occur concurrently
26 * from different threads. Uses shared_mutex for optimal read performance
27 * (multiple concurrent queries, exclusive write for registration).
28 *
29 * Lifecycle:
30 * 1. Backend initializes and registers services
31 * 2. Consumers query for services as needed
32 * 3. Backend shuts down and unregisters services
33 * 4. Registry remains valid for next backend initialization
34 *
35 * Example Usage:
36 *
37 * Backend registration:
38 * auto& registry = BackendRegistry::instance();
39 * registry.register_service<IBufferService>([this]() -> void* {
40 * return m_buffer_service.get();
41 * });
42 *
43 * Consumer query:
44 * auto* service = BackendRegistry::instance().get_service<IBufferService>();
45 * if (service) {
46 * service->create_buffer(...);
47 * }
48 */
49class MAYAFLUX_API BackendRegistry {
50public:
51 using ServiceId = std::type_index;
52 using ServiceFactory = std::function<void*()>;
53
54 /**
55 * @brief Get the global registry instance
56 * @return Reference to singleton registry
57 *
58 * Thread-safe initialization via static local variable (C++11 guarantee).
59 * Instance is never destroyed - lives for program duration.
60 */
62 {
63 static BackendRegistry registry;
64 return registry;
65 }
66
71
72 /**
73 * @brief Register a backend service capability
74 * @tparam Interface The service interface type being provided
75 * @param factory Factory function returning pointer to service implementation
76 *
77 * Thread-safe. Multiple registrations of the same interface type will
78 * overwrite previous registrations, enabling backend hot-swapping.
79 *
80 * The factory is called each time get_service() is invoked, allowing
81 * backends to return context-specific implementations if needed.
82 *
83 * Example:
84 * registry.register_service<IBufferService>([this]() -> void* {
85 * return static_cast<IBufferService*>(&m_buffer_service_impl);
86 * });
87 */
88 template <typename Interface>
90 {
91 std::unique_lock lock(m_mutex);
92 m_services[typeid(Interface)] = std::move(factory);
93 }
94
95 /**
96 * @brief Query for a backend service
97 * @tparam Interface The service interface type needed
98 * @return Pointer to service implementation or nullptr if unavailable
99 *
100 * Thread-safe. Returns nullptr if service not registered - callers
101 * must always check for nullptr before use.
102 *
103 * The returned pointer is valid as long as the backend remains alive.
104 * Do not cache pointers across backend lifetime boundaries.
105 *
106 * Example:
107 * auto* service = registry.get_service<IBufferService>();
108 * if (service) {
109 * auto buffer = service->create_buffer(...);
110 * } else {
111 * // Handle missing service gracefully
112 * }
113 */
114 template <typename Interface>
115 Interface* get_service()
116 {
117 std::shared_lock lock(m_mutex);
118 auto it = m_services.find(typeid(Interface));
119 if (it != m_services.end()) {
120 return static_cast<Interface*>(it->second());
121 }
122 return nullptr;
123 }
124
125 /**
126 * @brief Check if a service is available
127 * @tparam Interface The service interface type to check
128 * @return True if service is currently registered
129 *
130 * Thread-safe. Useful for capability detection without error handling.
131 * Note: Service availability can change between has_service() and
132 * get_service() calls due to concurrent unregistration.
133 *
134 * Example:
135 * if (registry.has_service<IComputeService>()) {
136 * // Compute shaders available
137 * }
138 */
139 template <typename Interface>
140 bool has_service() const
141 {
142 std::shared_lock lock(m_mutex);
143 return m_services.contains(typeid(Interface));
144 }
145
146 /**
147 * @brief Unregister a service
148 * @tparam Interface The service interface type to unregister
149 *
150 * Thread-safe. Typically called during backend shutdown.
151 * Safe to call even if service not registered (no-op).
152 * After unregistration, get_service() will return nullptr.
153 *
154 * Example:
155 * registry.unregister_service<IBufferService>();
156 */
157 template <typename Interface>
159 {
160 std::unique_lock lock(m_mutex);
161 m_services.erase(typeid(Interface));
162 }
163
164 /**
165 * @brief Clear all registered services
166 *
167 * Thread-safe. Useful for testing or complete system reset.
168 * Typically called during engine shutdown to ensure clean state.
169 */
171 {
172 std::unique_lock lock(m_mutex);
173 m_services.clear();
174 }
175
176 /**
177 * @brief Get count of currently registered services
178 * @return Number of registered service types
179 *
180 * Thread-safe. Primarily for debugging and diagnostics.
181 */
182 size_t get_service_count() const
183 {
184 std::shared_lock lock(m_mutex);
185 return m_services.size();
186 }
187
188private:
189 BackendRegistry() = default;
190 ~BackendRegistry() = default;
191
192 mutable std::shared_mutex m_mutex;
193 std::unordered_map<ServiceId, ServiceFactory> m_services;
194};
195
196} // namespace MayaFlux::Registry
Interface * get_service()
Query for a backend service.
void register_service(ServiceFactory factory)
Register a backend service capability.
BackendRegistry(const BackendRegistry &)=delete
BackendRegistry & operator=(const BackendRegistry &)=delete
std::function< void *()> ServiceFactory
std::unordered_map< ServiceId, ServiceFactory > m_services
BackendRegistry(BackendRegistry &&)=delete
size_t get_service_count() const
Get count of currently registered services.
BackendRegistry & operator=(BackendRegistry &&)=delete
bool has_service() const
Check if a service is available.
void clear_all_services()
Clear all registered services.
static BackendRegistry & instance()
Get the global registry instance.
void unregister_service()
Unregister a service.
Thread-safe singleton registry for backend service discovery.