header_utils
Loading...
Searching...
No Matches
di_impl.h
1
4
5#pragma once
6
7namespace ghassanpl::di
8{
9 namespace detail
10 {
12
13 template <class TArg>
14 struct ArgumentResolver;
15
16 template <class TArg>
17 struct ArgumentResolver<std::shared_ptr<TArg>>
18 {
19 typedef std::shared_ptr<TArg> Type;
20
21 template <typename CONTAINER>
22 static Type Resolve(CONTAINER& container)
23 {
24 return container.template Resolve<TArg>();
25 }
26 };
27
29 /*
30 template <class TArg>
31 struct ArgumentResolver<std::unique_ptr<TArg>>
32 {
33 typedef std::unique_ptr<TArg> Type;
34
35 template <typename CONTAINER>
36 static Type Resolve(CONTAINER& container)
37 {
38 return container.template Resolve<TArg>(ForceTransient);
39 }
40 };
41 */
42
43 template <class TArg>
44 struct ArgumentResolver<std::vector<std::shared_ptr<TArg>>>
45 {
46 typedef std::vector<std::shared_ptr<TArg>> Type;
47
48 template <typename CONTAINER>
49 static Type Resolve(CONTAINER& container)
50 {
51 return container.template ResolveAll<TArg>();
52 }
53 };
54
55 template <>
56 struct ArgumentResolver<Container&>
57 {
58 typedef Container& Type;
59
60 static Type Resolve(Container& container)
61 {
62 return container;
63 }
64 };
65
66 template <class T, class TArgumentPack>
67 struct ConstructorDescriptor;
68
69 template <class T>
70 struct ConstructorDescriptor<T, std::tuple<>>
71 {
72 static std::function<std::shared_ptr<T>(Container&)> CreateFactory()
73 {
74 return [](Container&) { return std::make_shared<T>(); };
75 }
76 static T* Create(Container& c)
77 {
78 return new T;
79 }
80 };
81
82 template <typename T>
83 concept IsSupportedArgument = requires (Container& cnt) { { ArgumentResolver<T>::Resolve(cnt) }; };
84
85 template <class T, class... TAnyArgument>
86 struct ConstructorDescriptor<T, std::tuple<TAnyArgument...>>
87 {
88 static std::function<std::shared_ptr<T>(Container&)> CreateFactory()
89 {
90 return [](Container& container) {
91 return std::make_shared<T>(ArgumentResolverInvoker<typename TAnyArgument::Type>(container)...);
92 };
93 }
94 static T* Create(Container& c)
95 {
96 return new T(ArgumentResolverInvoker<typename TAnyArgument::Type>(c)...);
97 }
98 };
99
100 struct ConstructorTypologyNotSupported
101 {
102 using Type = ConstructorTypologyNotSupported;
103 };
104
105 template <class TParent>
106 struct ArgumentResolverInvoker
107 {
108 explicit ArgumentResolverInvoker(Container& container) : mContainer(container) {}
109
110 template <class T>
111 requires (!std::is_convertible_v<TParent, T> && IsSupportedArgument<T>)
112 operator T()
113 {
114 return ArgumentResolver<T>::Resolve(mContainer);
115 }
116
117 template <class T>
118 requires (!std::is_convertible_v<TParent, T> && IsSupportedArgument<T&>)
119 operator T& ()
120 {
121 return ArgumentResolver<T&>::Resolve(mContainer);
122 }
123
124 private:
125
126 Container& mContainer;
127 };
128
129 template <class TParent>
130 struct AnyArgument
131 {
132 using Type = TParent;
133
134 template <class T>
135 requires (!std::is_convertible_v<TParent, T>&& IsSupportedArgument<T&>)
136 operator T& ()
137 {
138 }
139
140 template <class T>
141 requires (!std::is_convertible_v<TParent, T>&& IsSupportedArgument<T>)
142 operator T()
143 {
144 }
145 };
146
147 template <class T, int>
148 struct WrapAndGet : AnyArgument<T> {};
149
150 template <class, class>
151 struct ConstructorTypologyDeducer;
152
153 // Initial recursion state
154 template <typename T>
155 requires std::is_constructible_v<T>
156 struct ConstructorTypologyDeducer<T, std::integer_sequence<int>>
157 {
158 using Type = std::tuple<>;
159 };
160
161 template <class T>
162 requires (!std::is_constructible_v<T>)
163 struct ConstructorTypologyDeducer<T, std::integer_sequence<int>>
164 {
165 using Type = typename ConstructorTypologyDeducer<T, std::make_integer_sequence<int, 1>>::Type;
166 };
167
168 static constexpr inline size_t MaximumArgumentCount = 20;
169
170 // Common recusion state
171 template <class T, int... NthArgument>
172 requires (sizeof...(NthArgument) > 0 && sizeof...(NthArgument) < MaximumArgumentCount) && std::is_constructible_v<T, WrapAndGet<T, NthArgument>...>
173 struct ConstructorTypologyDeducer<T, std::integer_sequence<int, NthArgument...>>
174 {
175 using Type = std::tuple<WrapAndGet<T, NthArgument>...>;
176 };
177
178 template <class T, int... NthArgument>
179 requires (sizeof...(NthArgument) > 0 && sizeof...(NthArgument) < MaximumArgumentCount) && (!std::is_constructible_v<T, WrapAndGet<T, NthArgument>...>)
180 struct ConstructorTypologyDeducer<T, std::integer_sequence<int, NthArgument...>>
181 {
182 using Type = typename ConstructorTypologyDeducer<T, std::make_integer_sequence<int, sizeof...(NthArgument) + 1>>::Type;
183 };
184
185 // Last recursion state
186 template <class T, int... NthArgument>
187 requires (sizeof...(NthArgument) == MaximumArgumentCount) && std::is_constructible_v<T, WrapAndGet<T, NthArgument>...>
188 struct ConstructorTypologyDeducer<T, std::integer_sequence<int, NthArgument...>>
189 {
190 using Type = std::tuple<WrapAndGet<T, NthArgument>...>;
191 };
192
193 template <class T, int... NthArgument>
194 requires (sizeof...(NthArgument) == MaximumArgumentCount) && (!std::is_constructible_v<T, WrapAndGet<T, NthArgument>...>)
195 struct ConstructorTypologyDeducer<T, std::integer_sequence<int, NthArgument...>> : ConstructorTypologyNotSupported
196 {
197 };
198
199 template <typename T>
200 using ConstructorDescriptorForClass = ConstructorDescriptor<T, typename ConstructorTypologyDeducer<T, std::make_integer_sequence<int, 0>>::Type>;
201 }
202
203
204 template <typename INTERFACE>
205 struct Container::ImplementationContainer
206 {
207 Lifetime CustomLifetime = Lifetime::Default;
208 std::string Name;
209
210 std::shared_ptr<INTERFACE> StrongInstancePointer;
211 std::map<std::thread::id, std::shared_ptr<INTERFACE>> ThreadInstances;
212 mutable std::weak_ptr<INTERFACE> WeakInstancePointer;
213 std::function<std::shared_ptr<INTERFACE>(Container&)> mFactory;
214 std::function<void(Container&, std::shared_ptr<INTERFACE>)> mOnCreate;
215
217 void Set(std::string_view name) { Name = std::string{ name }; }
218 void Set(Lifetime lifetime) { CustomLifetime = lifetime; }
219 void Set(DefaultImplementationStruct) { }
220 template <std::derived_from<INTERFACE> T>
221 void Set(std::function<std::shared_ptr<T>(Container&)> factory)
222 {
223 mFactory = [factory = std::move(factory)](Container& container) {
224 return container.Instantiate<INTERFACE>(factory);
225 };
226 }
227 void Set(std::shared_ptr<INTERFACE> instance) { StrongInstancePointer = std::move(instance); }
228 void Set(INTERFACE* instance) { StrongInstancePointer = std::shared_ptr<INTERFACE>{ std::shared_ptr<INTERFACE>{}, instance }; }
229 void Set(std::function<void(Container&, std::shared_ptr<INTERFACE>)> on_create) { mOnCreate = std::move(on_create); }
230
231 std::shared_ptr<INTERFACE> Resolve(Container& container, Lifetime lifetime)
232 {
233 if (CustomLifetime != Lifetime::Default)
234 lifetime = CustomLifetime;
235
236 if (lifetime == Lifetime::ThreadSingleton)
237 {
238 auto& ptr = ThreadInstances[std::this_thread::get_id()];
239 if (!ptr)
240 ptr = Create(container);
241 return ptr;
242 }
243 else if (lifetime == Lifetime::WeakSingleton)
244 {
245 if (auto result = WeakInstancePointer.lock(); result)
246 return result;
247 auto ptr = Create(container);
248 WeakInstancePointer = ptr;
249 return ptr;
250 }
251 else if (lifetime == Lifetime::InstanceSingleton)
252 {
253 if (!StrongInstancePointer)
254 StrongInstancePointer = Create(container);
255 return StrongInstancePointer;
256 }
257
258 if (StrongInstancePointer)
259 return StrongInstancePointer;
260 return Create(container);
261 }
262
263 private:
264
265 void ResetInstance()
266 {
267 StrongInstancePointer.reset();
268 WeakInstancePointer.reset();
269 ThreadInstances.clear();
270 }
271
272 std::shared_ptr<INTERFACE> Create(Container& container) const
273 {
274 auto obj = mFactory(container);
275
276 if (!container.mDebugStore.contains(obj.get()))
277 container.mDebugStore.emplace(obj.get(), std::pair<std::type_index, std::weak_ptr<void>>{ typeid(*obj), std::weak_ptr<void>{obj} });
278
279 if (mOnCreate)
280 {
281 container.ReportCreation(obj, [this](Container& container, std::shared_ptr<void> instance) {
282 mOnCreate(container, std::static_pointer_cast<INTERFACE>(std::move(instance)));
283 });
284 }
285 return obj;
286 }
287
288 };
289
290 template <typename INTERFACE>
291 struct Container::InterfaceContainer : Container::BaseInterfaceContainer
292 {
293 template <typename I = INTERFACE>
294 static constexpr Lifetime GetDeclaredLifetime()
295 {
296 if constexpr (has_default_lifetime<I>)
297 return I::DefaultLifetime;
298 else
299 return Lifetime::Default;
300 }
301
302 InterfaceContainer() : BaseInterfaceContainer(GetDeclaredLifetime<INTERFACE>()) {}
303
304 template <typename IMPLEMENTATION, typename... ARGS>
305 void RegisterImplementationType(ARGS&&... args)
306 {
307 if (mImplementations.contains(typeid(IMPLEMENTATION)))
308 throw "already registered";
309
310 auto& impl = mImplementations[typeid(IMPLEMENTATION)];
311 if constexpr (is_any_of_v<DefaultImplementationStruct, ARGS...>)
312 mImplementationsInDeclarationOrder.insert(mImplementationsInDeclarationOrder.begin(), &impl);
313 else
314 mImplementationsInDeclarationOrder.push_back(&impl);
315
316 impl.Set(GetDeclaredLifetime<IMPLEMENTATION>());
317 (impl.Set(std::forward<ARGS>(args)), ...);
318 }
319
320 template <typename IMPLEMENTATION>
321 ImplementationContainer<INTERFACE>* GetImplementationContainer()
322 {
323 auto it = mImplementations.find(typeid(IMPLEMENTATION));
324 if (it == mImplementations.end())
325 return nullptr;
326 return &it->second;
327 }
328
329 std::shared_ptr<INTERFACE> Resolve(Container& container, Lifetime lifetime)
330 {
331 if (DefaultLifetime != Lifetime::Default)
332 lifetime = DefaultLifetime;
333
334 if (mImplementationsInDeclarationOrder.empty())
335 return {};
336
337 return mImplementationsInDeclarationOrder.back()->Resolve(container, lifetime);
338 }
339
340 std::vector<std::shared_ptr<INTERFACE>> ResolveAll(Container& container, Lifetime lifetime)
341 {
342 std::vector<std::shared_ptr<INTERFACE>> result;
343
344 for (auto& [type, impl] : mImplementations)
345 result.push_back(impl.Resolve(container, lifetime));
346
347 return result;
348 }
349
350 virtual bool HasAnyImplementations() const override {
351 return !mImplementations.empty();
352 }
353
354 private:
355
356 std::map<std::type_index, ImplementationContainer<INTERFACE>> mImplementations;
357 std::vector<ImplementationContainer<INTERFACE>*> mImplementationsInDeclarationOrder;
358
359 };
360
361 template <typename INTERFACE>
363 {
364 if (auto it = mContainers.find(typeid(INTERFACE)); it != mContainers.end())
365 return it->second->HasAnyImplementations();
366 return false;
367 }
368
369 template<typename INTERFACE, typename IMPLEMENTATION, typename ...PROPS>
370 void Container::RegisterType(PROPS&& ...properties)
371 {
374 static_assert(std::is_base_of_v<INTERFACE, IMPLEMENTATION>, "Implementation class must inherit from interface class");
375 static_assert(!std::is_abstract_v<IMPLEMENTATION>, "Implementation cannot be abstract");
376 if constexpr (std::is_base_of_v<INTERFACE, IMPLEMENTATION> && !std::is_abstract_v<IMPLEMENTATION>)
377 {
378 constexpr auto instance_given = is_any_of_v<std::shared_ptr<IMPLEMENTATION>, PROPS...>;
379 constexpr auto interface_factory = is_any_of_v<std::function<std::shared_ptr<INTERFACE>(Container&)>, PROPS...>;
380 constexpr auto impl_factory = is_any_of_v<std::function<std::shared_ptr<IMPLEMENTATION>(Container&)>, PROPS...>;
381 static_assert(!(instance_given && (interface_factory || impl_factory)), "Cannot register type with both factory and instance");
382 if constexpr (instance_given || interface_factory || impl_factory)
383 GetInterfaceContainer<INTERFACE>().template RegisterImplementationType<IMPLEMENTATION>(std::forward<PROPS>(properties)...);
384 else
385 GetInterfaceContainer<INTERFACE>().template RegisterImplementationType<IMPLEMENTATION>(detail::ConstructorDescriptorForClass<IMPLEMENTATION>::CreateFactory(), std::forward<PROPS>(properties)...);
386 }
387 }
388
389 template<typename INTERFACE>
390 std::shared_ptr<INTERFACE> Container::Resolve()
391 {
392 return GetInterfaceContainer<INTERFACE>().Resolve(*this, DefaultLifetime);
393 }
394
395 template<typename INTERFACE>
396 std::shared_ptr<INTERFACE> Container::ResolveByName(std::string_view name)
397 {
398 auto& interface_container = GetInterfaceContainer<INTERFACE>();
399 for (auto& impl : interface_container.mImplementations)
400 {
401 if (impl.Name == name)
402 return impl.Resolve(*this, DefaultLifetime);
403 }
404 return {};
405 }
406
407 template<typename INTERFACE>
408 std::vector<std::shared_ptr<INTERFACE>> Container::ResolveAll()
409 {
410 return GetInterfaceContainer<INTERFACE>().ResolveAll(*this, DefaultLifetime);
411 }
412
413 template <typename TYPE>
414 std::shared_ptr<TYPE> Container::Create()
415 {
416 return std::shared_ptr<TYPE>{ detail::ConstructorDescriptorForClass<TYPE>::Create(*this) };
417 }
418
419 template <typename TYPE>
420 std::unique_ptr<TYPE> Container::CreateRaw()
421 {
422 return std::unique_ptr<TYPE>{ detail::ConstructorDescriptorForClass<TYPE>::Create(*this) };
423 }
424
425 template<typename INTERFACE>
426 Container::InterfaceContainer<INTERFACE>& Container::GetInterfaceContainer()
427 {
428 auto& container = mContainers[typeid(INTERFACE)];
429 if (!container)
430 container = std::make_unique<InterfaceContainer<INTERFACE>>();
431 return *static_cast<InterfaceContainer<INTERFACE>*>(container.get());
432 }
433
434 template<typename INTERFACE, typename IMPLEMENTATION>
435 Container::ImplementationContainer<INTERFACE>* Container::GetImplementationContainer()
436 {
437 return GetInterfaceContainer<INTERFACE>().template GetImplementationContainer<IMPLEMENTATION>();
438 }
439
440 template<typename INSTANCE>
441 void Container::ReportCreation(std::shared_ptr<INSTANCE> const& obj, std::function<void(Container&, std::shared_ptr<void>)> func)
442 {
443 for (auto& [ptr, callback] : mCreationsToReport)
444 {
445 if (ptr.get() == obj.get())
446 return;
447 }
448 mCreationsToReport.emplace_back(static_pointer_cast<void>(obj), std::move(func));
449 }
450
451 template<typename INTERFACE, typename T>
452 std::shared_ptr<INTERFACE> Container::Instantiate(T& factory)
453 {
454 if (find(mResolutionStack.begin(), mResolutionStack.end(), typeid(INTERFACE)) != mResolutionStack.end())
455 throw "circular dependency";
456 mResolutionStack.push_back(typeid(INTERFACE));
457
458 auto result = factory(*this);
459
460 mResolutionStack.pop_back();
461 if (mResolutionStack.empty())
462 ReportAwaitingCreations();
463
464 return std::static_pointer_cast<INTERFACE>(std::move(result));
465 }
466
467}
Lifetime
Specifies the lifetime of an implementation.
Definition di.h:37
@ WeakSingleton
Same as InstanceSingleton, but will not hold on to an instance, so when your last shared_ptr to it wi...
Definition di.h:41
@ InstanceSingleton
If a singleton instance of the implementation has not yet been created, it will be created and return...
Definition di.h:40
@ ThreadSingleton
Same as InstanceSingleton, but each thread gets its own instance.
Definition di.h:42
@ Default
Does not specify which lifetime of the implementation you want; you will be given one that's availabl...
Definition di.h:38
The container for implementations; used to request interfaces.
Definition di.h:55
std::shared_ptr< TYPE > Create()
Creates a new (shared pointer to an) object of TYPE, resolving any interface pointer parameters its c...
Definition di_impl.h:414
std::shared_ptr< INTERFACE > Resolve()
Returns a pointer to an implementation of INTERFACE.
Definition di_impl.h:390
std::unique_ptr< TYPE > CreateRaw()
Same as Create, but returns a unique_ptr to the new object.
Definition di_impl.h:420
std::vector< std::shared_ptr< INTERFACE > > ResolveAll()
Will return a vector of all available implementations of INTERFACE; useful for interfaces like image_...
Definition di_impl.h:408
std::shared_ptr< INTERFACE > ResolveByName(std::string_view name)
Returns a pointer to an implementation of INTERFACE with the name name If an implementation with that...
Definition di_impl.h:396
bool HasAnyImplementationsOf() const
Checks if there are any implementation registered for INTERFACE.
Definition di_impl.h:362
Lifetime DefaultLifetime
The default lifetime of implementations in this container, unless specified otherwise by the interfac...
Definition di.h:57
void RegisterType(PROPS &&... properties)
Registers the type IMPLEMENTATION as an implementation of INTERFACE.
Definition di_impl.h:370