14 struct ArgumentResolver;
17 struct ArgumentResolver<std::shared_ptr<TArg>>
19 typedef std::shared_ptr<TArg> Type;
21 template <
typename CONTAINER>
22 static Type Resolve(CONTAINER& container)
24 return container.template Resolve<TArg>();
44 struct ArgumentResolver<std::vector<std::shared_ptr<TArg>>>
46 typedef std::vector<std::shared_ptr<TArg>> Type;
48 template <
typename CONTAINER>
49 static Type Resolve(CONTAINER& container)
51 return container.template ResolveAll<TArg>();
56 struct ArgumentResolver<Container&>
58 typedef Container& Type;
60 static Type Resolve(Container& container)
66 template <
class T,
class TArgumentPack>
67 struct ConstructorDescriptor;
70 struct ConstructorDescriptor<T, std::tuple<>>
72 static std::function<std::shared_ptr<T>(Container&)> CreateFactory()
74 return [](Container&) {
return std::make_shared<T>(); };
76 static T* Create(Container& c)
83 concept IsSupportedArgument =
requires (Container& cnt) { { ArgumentResolver<T>::Resolve(cnt) }; };
85 template <
class T,
class... TAnyArgument>
86 struct ConstructorDescriptor<T, std::tuple<TAnyArgument...>>
88 static std::function<std::shared_ptr<T>(Container&)> CreateFactory()
90 return [](Container& container) {
91 return std::make_shared<T>(ArgumentResolverInvoker<typename TAnyArgument::Type>(container)...);
94 static T* Create(Container& c)
96 return new T(ArgumentResolverInvoker<typename TAnyArgument::Type>(c)...);
100 struct ConstructorTypologyNotSupported
102 using Type = ConstructorTypologyNotSupported;
105 template <
class TParent>
106 struct ArgumentResolverInvoker
108 explicit ArgumentResolverInvoker(Container& container) : mContainer(container) {}
111 requires (!std::is_convertible_v<TParent, T> && IsSupportedArgument<T>)
114 return ArgumentResolver<T>::Resolve(mContainer);
118 requires (!std::is_convertible_v<TParent, T> && IsSupportedArgument<T&>)
121 return ArgumentResolver<T&>::Resolve(mContainer);
126 Container& mContainer;
129 template <
class TParent>
132 using Type = TParent;
135 requires (!std::is_convertible_v<TParent, T>&& IsSupportedArgument<T&>)
141 requires (!std::is_convertible_v<TParent, T>&& IsSupportedArgument<T>)
147 template <
class T,
int>
148 struct WrapAndGet : AnyArgument<T> {};
150 template <
class,
class>
151 struct ConstructorTypologyDeducer;
154 template <
typename T>
155 requires std::is_constructible_v<T>
156 struct ConstructorTypologyDeducer<T, std::integer_sequence<int>>
158 using Type = std::tuple<>;
162 requires (!std::is_constructible_v<T>)
163 struct ConstructorTypologyDeducer<T, std::integer_sequence<int>>
165 using Type =
typename ConstructorTypologyDeducer<T, std::make_integer_sequence<int, 1>>::Type;
168 static constexpr inline size_t MaximumArgumentCount = 20;
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...>>
175 using Type = std::tuple<WrapAndGet<T, NthArgument>...>;
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...>>
182 using Type =
typename ConstructorTypologyDeducer<T, std::make_integer_sequence<int,
sizeof...(NthArgument) + 1>>::Type;
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...>>
190 using Type = std::tuple<WrapAndGet<T, NthArgument>...>;
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
199 template <
typename T>
200 using ConstructorDescriptorForClass = ConstructorDescriptor<T, typename ConstructorTypologyDeducer<T, std::make_integer_sequence<int, 0>>::Type>;
204 template <
typename INTERFACE>
205 struct Container::ImplementationContainer
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;
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)
223 mFactory = [factory = std::move(factory)](Container& container) {
224 return container.Instantiate<INTERFACE>(factory);
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); }
231 std::shared_ptr<INTERFACE>
Resolve(Container& container,
Lifetime lifetime)
234 lifetime = CustomLifetime;
238 auto& ptr = ThreadInstances[std::this_thread::get_id()];
245 if (
auto result = WeakInstancePointer.lock(); result)
247 auto ptr =
Create(container);
248 WeakInstancePointer = ptr;
253 if (!StrongInstancePointer)
254 StrongInstancePointer =
Create(container);
255 return StrongInstancePointer;
258 if (StrongInstancePointer)
259 return StrongInstancePointer;
267 StrongInstancePointer.reset();
268 WeakInstancePointer.reset();
269 ThreadInstances.clear();
272 std::shared_ptr<INTERFACE>
Create(Container& container)
const
274 auto obj = mFactory(container);
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} });
281 container.ReportCreation(obj, [
this](Container& container, std::shared_ptr<void> instance) {
282 mOnCreate(container, std::static_pointer_cast<INTERFACE>(std::move(instance)));
290 template <
typename INTERFACE>
291 struct Container::InterfaceContainer : Container::BaseInterfaceContainer
293 template <
typename I = INTERFACE>
294 static constexpr Lifetime GetDeclaredLifetime()
296 if constexpr (has_default_lifetime<I>)
297 return I::DefaultLifetime;
299 return Lifetime::Default;
302 InterfaceContainer() : BaseInterfaceContainer(GetDeclaredLifetime<INTERFACE>()) {}
304 template <
typename IMPLEMENTATION,
typename... ARGS>
305 void RegisterImplementationType(ARGS&&... args)
307 if (mImplementations.contains(
typeid(IMPLEMENTATION)))
308 throw "already registered";
310 auto& impl = mImplementations[
typeid(IMPLEMENTATION)];
311 if constexpr (is_any_of_v<DefaultImplementationStruct, ARGS...>)
312 mImplementationsInDeclarationOrder.insert(mImplementationsInDeclarationOrder.begin(), &impl);
314 mImplementationsInDeclarationOrder.push_back(&impl);
316 impl.Set(GetDeclaredLifetime<IMPLEMENTATION>());
317 (impl.Set(std::forward<ARGS>(args)), ...);
320 template <
typename IMPLEMENTATION>
321 ImplementationContainer<INTERFACE>* GetImplementationContainer()
323 auto it = mImplementations.find(
typeid(IMPLEMENTATION));
324 if (it == mImplementations.end())
329 std::shared_ptr<INTERFACE> Resolve(Container& container, Lifetime lifetime)
331 if (DefaultLifetime != Lifetime::Default)
332 lifetime = DefaultLifetime;
334 if (mImplementationsInDeclarationOrder.empty())
337 return mImplementationsInDeclarationOrder.back()->Resolve(container, lifetime);
340 std::vector<std::shared_ptr<INTERFACE>> ResolveAll(Container& container, Lifetime lifetime)
342 std::vector<std::shared_ptr<INTERFACE>> result;
344 for (
auto& [type, impl] : mImplementations)
345 result.push_back(impl.Resolve(container, lifetime));
350 virtual bool HasAnyImplementations()
const override {
351 return !mImplementations.empty();
356 std::map<std::type_index, ImplementationContainer<INTERFACE>> mImplementations;
357 std::vector<ImplementationContainer<INTERFACE>*> mImplementationsInDeclarationOrder;
361 template <
typename INTERFACE>
364 if (
auto it = mContainers.find(
typeid(INTERFACE)); it != mContainers.end())
365 return it->second->HasAnyImplementations();
369 template<
typename INTERFACE,
typename IMPLEMENTATION,
typename ...PROPS>
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>)
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)...);
385 GetInterfaceContainer<INTERFACE>().template RegisterImplementationType<IMPLEMENTATION>(detail::ConstructorDescriptorForClass<IMPLEMENTATION>::CreateFactory(), std::forward<PROPS>(properties)...);
389 template<
typename INTERFACE>
392 return GetInterfaceContainer<INTERFACE>().Resolve(*
this,
DefaultLifetime);
395 template<
typename INTERFACE>
398 auto& interface_container = GetInterfaceContainer<INTERFACE>();
399 for (
auto&
impl : interface_container.mImplementations)
401 if (
impl.Name == name)
407 template<
typename INTERFACE>
410 return GetInterfaceContainer<INTERFACE>().ResolveAll(*
this,
DefaultLifetime);
413 template <
typename TYPE>
416 return std::shared_ptr<TYPE>{ detail::ConstructorDescriptorForClass<TYPE>::Create(*
this) };
419 template <
typename TYPE>
422 return std::unique_ptr<TYPE>{ detail::ConstructorDescriptorForClass<TYPE>::Create(*
this) };
425 template<
typename INTERFACE>
426 Container::InterfaceContainer<INTERFACE>& Container::GetInterfaceContainer()
428 auto& container = mContainers[
typeid(INTERFACE)];
430 container = std::make_unique<InterfaceContainer<INTERFACE>>();
431 return *
static_cast<InterfaceContainer<INTERFACE>*
>(container.get());
434 template<
typename INTERFACE,
typename IMPLEMENTATION>
435 Container::ImplementationContainer<INTERFACE>* Container::GetImplementationContainer()
437 return GetInterfaceContainer<INTERFACE>().template GetImplementationContainer<IMPLEMENTATION>();
440 template<
typename INSTANCE>
441 void Container::ReportCreation(std::shared_ptr<INSTANCE>
const& obj, std::function<
void(Container&, std::shared_ptr<void>)> func)
443 for (
auto& [ptr, callback] : mCreationsToReport)
445 if (ptr.get() == obj.get())
448 mCreationsToReport.emplace_back(static_pointer_cast<void>(obj), std::move(func));
451 template<
typename INTERFACE,
typename T>
452 std::shared_ptr<INTERFACE> Container::Instantiate(T& factory)
454 if (find(mResolutionStack.begin(), mResolutionStack.end(),
typeid(INTERFACE)) != mResolutionStack.end())
455 throw "circular dependency";
456 mResolutionStack.push_back(
typeid(INTERFACE));
458 auto result = factory(*
this);
460 mResolutionStack.pop_back();
461 if (mResolutionStack.empty())
462 ReportAwaitingCreations();
464 return std::static_pointer_cast<INTERFACE>(std::move(result));
Lifetime
Specifies the lifetime of an implementation.
@ WeakSingleton
Same as InstanceSingleton, but will not hold on to an instance, so when your last shared_ptr to it wi...
@ InstanceSingleton
If a singleton instance of the implementation has not yet been created, it will be created and return...
@ ThreadSingleton
Same as InstanceSingleton, but each thread gets its own instance.
@ Default
Does not specify which lifetime of the implementation you want; you will be given one that's availabl...
The container for implementations; used to request interfaces.
std::shared_ptr< TYPE > Create()
Creates a new (shared pointer to an) object of TYPE, resolving any interface pointer parameters its c...
std::shared_ptr< INTERFACE > Resolve()
Returns a pointer to an implementation of INTERFACE.
std::unique_ptr< TYPE > CreateRaw()
Same as Create, but returns a unique_ptr to the new object.
std::vector< std::shared_ptr< INTERFACE > > ResolveAll()
Will return a vector of all available implementations of INTERFACE; useful for interfaces like image_...
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...
bool HasAnyImplementationsOf() const
Checks if there are any implementation registered for INTERFACE.
Lifetime DefaultLifetime
The default lifetime of implementations in this container, unless specified otherwise by the interfac...
void RegisterType(PROPS &&... properties)
Registers the type IMPLEMENTATION as an implementation of INTERFACE.