Arcane  v3.14.10.0
Documentation utilisateur
Chargement...
Recherche...
Aucune correspondance
DependencyInjection.h
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2024 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com)
4// See the top-level COPYRIGHT file for details.
5// SPDX-License-Identifier: Apache-2.0
6//-----------------------------------------------------------------------------
7/*---------------------------------------------------------------------------*/
8/* DependencyInjection.h (C) 2000-2024 */
9/* */
10/* Types et fonctions pour gérer le pattern 'DependencyInjection'. */
11/*---------------------------------------------------------------------------*/
12#ifndef ARCANE_UTILS_DEPENDENCYINJECTION_H
13#define ARCANE_UTILS_DEPENDENCYINJECTION_H
14/*---------------------------------------------------------------------------*/
15/*---------------------------------------------------------------------------*/
16
17/*
18 * NOTE: API en cours de définition. Ne pas utiliser.
19 */
20
21#include "arcane/utils/Ref.h"
22#include "arcane/utils/ExternalRef.h"
23#include "arcane/utils/GenericRegisterer.h"
24
26
27//TODO Mettre le lancement des exceptions dans le '.cc'
28#include "arcane/utils/NotImplementedException.h"
29
30#include <tuple>
31#include <typeinfo>
32
33// TODO: Améliorer les messages d'erreurs en cas d'échec de l'injection
34// TODO: Ajouter méthodes pour afficher le type en cas d'erreur (utiliser A_FUNC_INFO)
35// TODO: Ajouter mode verbose
36// TODO: Supporter plusieurs constructeurs et ne pas échouer si le premier
37// ne fonctionne pas
38// TODO: Supporter des instances externes (comme par exemple celles créées en C#).
39
40/*---------------------------------------------------------------------------*/
41/*---------------------------------------------------------------------------*/
42
43namespace Arcane::DependencyInjection
44{
45class Injector;
46}
47
48namespace Arcane::DependencyInjection::impl
49{
50class FactoryInfo;
51class IInstanceFactory;
52template <typename InterfaceType>
54class ConcreteFactoryTypeInfo;
55} // namespace Arcane::DependencyInjection::impl
56
57ARCCORE_DECLARE_REFERENCE_COUNTED_CLASS(Arcane::DependencyInjection::impl::IInstanceFactory)
58
59/*---------------------------------------------------------------------------*/
60/*---------------------------------------------------------------------------*/
61
62namespace Arcane::DependencyInjection
63{
64
65/*---------------------------------------------------------------------------*/
66/*---------------------------------------------------------------------------*/
67
68class ARCANE_UTILS_EXPORT IInjectedInstance
69{
70 public:
71 virtual ~IInjectedInstance() = default;
72 virtual bool hasName(const String& str) const = 0;
73 virtual bool hasTypeInfo(const std::type_info& tinfo) const = 0;
74};
75
76/*---------------------------------------------------------------------------*/
77/*---------------------------------------------------------------------------*/
78/*!
79 * \internal
80 * \warning Cette classe est utilisées dans des constructeurs/destructeurs
81 * globaux et ne doit pas faire d'allocation/désallocation ni utiliser de
82 * types qui en font.
83 */
84class ARCANE_UTILS_EXPORT ProviderProperty
85{
86 public:
87 ProviderProperty(const char* name)
88 : m_name(name)
89 {}
90
91 public:
92 const char* name() const { return m_name; }
93
94 private:
95 const char* m_name;
96};
97
98/*---------------------------------------------------------------------------*/
99/*---------------------------------------------------------------------------*/
100
101} // namespace Arcane::DependencyInjection
102
103/*---------------------------------------------------------------------------*/
104/*---------------------------------------------------------------------------*/
105
106namespace Arcane::DependencyInjection::impl
107{
108
109/*---------------------------------------------------------------------------*/
110/*---------------------------------------------------------------------------*/
111
112class TypeInfo
113{
114 private:
115 TypeInfo(const TraceInfo& trace_info, const std::type_info& type_info)
116 : m_trace_info(trace_info)
117 , m_type_info(type_info)
118 {}
119
120 public:
121 template <typename Type> static TypeInfo create()
122 {
123 return TypeInfo(A_FUNCINFO, typeid(Type));
124 }
125 const TraceInfo& traceInfo() const { return m_trace_info; }
126 const std::type_info& stdTypeInfo() const { return m_type_info; }
127
128 private:
129 TraceInfo m_trace_info;
130 const std::type_info& m_type_info;
131};
132
133/*---------------------------------------------------------------------------*/
134/*---------------------------------------------------------------------------*/
135/*!
136 * \brief Informations sur les types d'une fabrique.
137 *
138 * Cela permet d'afficher par exemple en cas d'erreur les informations sur
139 * l'interface concernée, le type concret qu'on souhaité créer et les
140 * paramètres du constructeur.
141 */
142class ARCANE_UTILS_EXPORT ConcreteFactoryTypeInfo
143{
144 private:
145 ConcreteFactoryTypeInfo(TypeInfo&& a, TypeInfo&& b, TypeInfo&& c)
146 : m_interface_info(a)
147 , m_concrete_info(b)
148 , m_constructor_info(c)
149 {}
150
151 public:
152 template <typename InterfaceType, typename ConcreteType, typename ConstructorType>
153 static ConcreteFactoryTypeInfo create()
154 {
155 return ConcreteFactoryTypeInfo(TypeInfo::create<InterfaceType>(),
156 TypeInfo::create<ConcreteType>(),
157 TypeInfo::create<ConstructorType>());
158 }
159 const TypeInfo& interfaceTypeInfo() const { return m_interface_info; }
160 const TypeInfo& concreteTypeInfo() const { return m_concrete_info; }
161 const TypeInfo& constructorTypeInfo() const { return m_constructor_info; }
162
163 private:
164 TypeInfo m_interface_info;
165 TypeInfo m_concrete_info;
166 TypeInfo m_constructor_info;
167};
168
169/*---------------------------------------------------------------------------*/
170/*---------------------------------------------------------------------------*/
171/*!
172 * \internal
173 * \brief Interface typée gérant l'instance d'un service.
174 */
175template <typename InterfaceType>
176class IInjectedRefInstanceT
177: public IInjectedInstance
178{
179 public:
180 virtual Ref<InterfaceType> instance() = 0;
181
182 private:
183};
184
185/*---------------------------------------------------------------------------*/
186/*---------------------------------------------------------------------------*/
187/*!
188 * \internal
189 * \brief Interface typée gérant l'instance d'un service.
190 */
191template <typename InterfaceType>
192class InjectedRefInstance
193: public IInjectedRefInstanceT<InterfaceType>
194{
195 public:
196 using InstanceType = Ref<InterfaceType>;
197
198 public:
199 InjectedRefInstance(InstanceType t_instance, const String& t_name)
200 : m_instance(t_instance)
201 , m_name(t_name)
202 {}
203
204 public:
205 Ref<InterfaceType> instance() override { return m_instance; }
206 bool hasName(const String& str) const override { return m_name == str; }
207 bool hasTypeInfo(const std::type_info& tinfo) const override { return typeid(InstanceType) == tinfo; }
208
209 private:
210 InstanceType m_instance;
211 String m_name;
212};
213
214/*---------------------------------------------------------------------------*/
215/*---------------------------------------------------------------------------*/
216/*!
217 * \internal
218 * \brief Interface typée gérant une instance
219 */
220template <typename Type>
221class IInjectedValueInstance
222: public IInjectedInstance
223{
224 public:
225 virtual Type instance() const = 0;
226
227 private:
228};
229
230/*---------------------------------------------------------------------------*/
231/*---------------------------------------------------------------------------*/
232/*!
233 * \internal
234 * \brief Interface typée gérant l'instance d'un service.
235 */
236template <typename Type>
237class InjectedValueInstance
238: public IInjectedValueInstance<Type>
239{
240 public:
241 using InstanceType = Type;
242
243 public:
244 InjectedValueInstance(Type t_instance, const String& t_name)
245 : m_instance(t_instance)
246 , m_name(t_name)
247 {}
248
249 public:
250 Type instance() const override { return m_instance; }
251 bool hasName(const String& str) const override { return m_name == str; }
252 bool hasTypeInfo(const std::type_info& tinfo) const override { return typeid(InstanceType) == tinfo; }
253
254 private:
255 Type m_instance;
256 String m_name;
257};
258
259/*---------------------------------------------------------------------------*/
260/*---------------------------------------------------------------------------*/
261/*!
262 * \brief Référence sur une instance injectée.
263 *
264 * Cette classe est gérée via un compteur de référence à la manière
265 * de la classe std::shared_ptr.
266 */
267class ARCANE_UTILS_EXPORT InjectedInstanceRef
268{
269 typedef Ref<IInjectedInstance> RefType;
270
271 private:
272 InjectedInstanceRef(const RefType& r)
273 : m_instance(r)
274 {}
275
276 public:
277 InjectedInstanceRef() = default;
278
279 public:
280 static InjectedInstanceRef createRef(IInjectedInstance* p)
281 {
282 return InjectedInstanceRef(RefType::create(p));
283 }
284 static InjectedInstanceRef createRefNoDestroy(IInjectedInstance* p)
285 {
286 return InjectedInstanceRef(RefType::_createNoDestroy(p));
287 }
288 static InjectedInstanceRef createWithHandle(IInjectedInstance* p, Internal::ExternalRef handle)
289 {
290 return InjectedInstanceRef(RefType::createWithHandle(p, handle));
291 }
292
293 public:
294 IInjectedInstance* get() const { return m_instance.get(); }
295 void reset() { m_instance.reset(); }
296
297 private:
298 RefType m_instance;
299};
300
301/*---------------------------------------------------------------------------*/
302/*---------------------------------------------------------------------------*/
303/*!
304 * \internal
305 * \brief Fabrique pour une instance encapsulée par une référence (i.e Ref<T>).
306 */
307class ARCANE_UTILS_EXPORT IInstanceFactory
308{
310
311 protected:
312 virtual ~IInstanceFactory() = default;
313
314 public:
315 virtual InjectedInstanceRef createGenericReference(Injector& injector, const String& name) = 0;
316
317 virtual const FactoryInfo* factoryInfo() const = 0;
318
319 virtual ConcreteFactoryTypeInfo concreteFactoryInfo() const = 0;
320
321 virtual Int32 nbConstructorArg() const = 0;
322};
323
324/*---------------------------------------------------------------------------*/
325/*---------------------------------------------------------------------------*/
326/*!
327 * \brief internal.
328 * \brief Classe de base pour une fabrique.
329 *
330 * Cette classe s'utiliser via un ReferenceCounter pour gérer sa destruction.
331 */
332class ARCANE_UTILS_EXPORT AbstractInstanceFactory
333: public ReferenceCounterImpl
334, public IInstanceFactory
335{
337};
338
339/*---------------------------------------------------------------------------*/
340/*---------------------------------------------------------------------------*/
341
342template <typename InterfaceType>
343class InstanceFactory
344: public AbstractInstanceFactory
345{
346 public:
347 InstanceFactory(FactoryInfo* si, IConcreteFactory<InterfaceType>* sub_factory)
348 : m_factory_info(si)
349 , m_sub_factory(sub_factory)
350 {
351 }
352
353 ~InstanceFactory() override
354 {
355 delete m_sub_factory;
356 }
357
358 InjectedInstanceRef createGenericReference(Injector& injector, const String& name) override
359 {
360 return _create(_createReference(injector), name);
361 }
362
363 Ref<InterfaceType> createReference(Injector& injector)
364 {
365 return _createReference(injector);
366 }
367
368 const FactoryInfo* factoryInfo() const override
369 {
370 return m_factory_info;
371 }
372
373 ConcreteFactoryTypeInfo concreteFactoryInfo() const override
374 {
375 return m_sub_factory->concreteFactoryInfo();
376 }
377
378 Int32 nbConstructorArg() const override
379 {
380 return m_sub_factory->nbConstructorArg();
381 }
382
383 protected:
384 FactoryInfo* m_factory_info;
385 IConcreteFactory<InterfaceType>* m_sub_factory;
386
387 private:
388 Ref<InterfaceType> _createReference(Injector& injector)
389 {
390 return m_sub_factory->createReference(injector);
391 }
392
393 InjectedInstanceRef _create(Ref<InterfaceType> it, const String& name)
394 {
395 IInjectedInstance* x = (!it) ? nullptr : new InjectedRefInstance<InterfaceType>(it, name);
396 return InjectedInstanceRef::createRef(x);
397 }
398};
399
400/*---------------------------------------------------------------------------*/
401/*---------------------------------------------------------------------------*/
402
403class ARCANE_UTILS_EXPORT IConcreteFactoryBase
404{
405 public:
406 virtual ~IConcreteFactoryBase() = default;
407
408 public:
409 virtual ConcreteFactoryTypeInfo concreteFactoryInfo() const = 0;
410 virtual Int32 nbConstructorArg() const = 0;
411};
412
413/*---------------------------------------------------------------------------*/
414/*---------------------------------------------------------------------------*/
415/*!
416 * \internal
417 * \brief Interface d'un fonctor de création d'une instance de service
418 * correspondant à l'interface \a InterfaceType.
419 */
420template <typename InterfaceType>
421class IConcreteFactory
422: public IConcreteFactoryBase
423{
424 public:
425 virtual ~IConcreteFactory() = default;
426
427 public:
428 //! Créé une instance du service .
429 virtual Ref<InterfaceType> createReference(Injector&) = 0;
430};
431
432/*---------------------------------------------------------------------------*/
433/*---------------------------------------------------------------------------*/
434/*!
435 * \internal
436 * \brief Informations pour une fabrique.
437 */
438class ARCANE_UTILS_EXPORT FactoryInfo
439{
440 friend class Arcane::DependencyInjection::Injector;
441 class Impl;
442
443 public:
444 FactoryInfo(const FactoryInfo&) = delete;
445 FactoryInfo& operator=(const FactoryInfo&) = delete;
446 ~FactoryInfo();
447
448 private:
449 FactoryInfo(const ProviderProperty& property);
450
451 public:
452 static FactoryInfo* create(const ProviderProperty& property, const char* file_name, int line_number)
453 {
454 ARCANE_UNUSED(file_name);
455 ARCANE_UNUSED(line_number);
456 return new FactoryInfo(property);
457 }
458 void addFactory(Ref<IInstanceFactory> f);
459 bool hasName(const String& str) const;
460
461 private:
462 Impl* m_p = nullptr;
463};
464
465/*---------------------------------------------------------------------------*/
466/*---------------------------------------------------------------------------*/
467
468class ARCANE_UTILS_EXPORT GlobalRegisterer
469: public GenericRegisterer<GlobalRegisterer>
470{
471 using BaseClass = GenericRegisterer<GlobalRegisterer>;
472 static BaseClass::Info m_global_registerer_info;
473
474 public:
475
476 static GenericRegisterer<GlobalRegisterer>::Info& registererInfo()
477 {
478 return m_global_registerer_info;
479 }
480
481 public:
482
483 typedef FactoryInfo* (*FactoryCreateFunc)(const ProviderProperty& property);
484
485 public:
486 /*!
487 * \brief Crée en enregistreur pour le service \a name et la fonction \a func.
488 *
489 * Ce constructeur est utilisé pour enregistrer un service.
490 */
491 GlobalRegisterer(FactoryCreateFunc func, const ProviderProperty& property) noexcept;
492
493 public:
494
495 FactoryCreateFunc infoCreatorWithPropertyFunction() { return m_factory_create_func; }
496
497 //! Nom du service
498 const char* name() { return m_name; }
499
500 const ProviderProperty& property() const { return m_factory_property; }
501
502 private:
503
504 FactoryCreateFunc m_factory_create_func = nullptr;
505 const char* m_name = nullptr;
506 ProviderProperty m_factory_property;
507
508 private:
509};
510
511/*---------------------------------------------------------------------------*/
512/*---------------------------------------------------------------------------*/
513
514} // namespace Arcane::DependencyInjection::impl
515
516namespace Arcane::DependencyInjection
517{
518
519/*---------------------------------------------------------------------------*/
520/*---------------------------------------------------------------------------*/
521/*!
522 * \brief Injecteur
523 */
524class ARCANE_UTILS_EXPORT Injector
525{
526 class Impl;
527
528 template <class Type>
529 class InjectorHelper
530 {
531 public:
532 static IInjectedInstance* bind(const Type& t, const String& name)
533 {
534 return new impl::InjectedValueInstance<Type>(t, name);
535 }
536 static Type get(Injector& i, const String& name)
537 {
538 return i._getValue<Type>(name);
539 }
540 };
541
542 //! Spécialisation pour les 'Ref'.
543 template <class PointerType>
544 class InjectorHelper<Ref<PointerType>>
545 {
546 public:
547 using ThatType = Ref<PointerType>;
548
549 public:
550 static IInjectedInstance* bind(const ThatType& t, const String& name)
551 {
552 return new impl::InjectedRefInstance<PointerType>(t, name);
553 }
554 static ThatType get(Injector& i, const String& name)
555 {
556 return i._getRef<PointerType>(name);
557 }
558 };
559 /*!
560 * \brief Interface d'un fonctor pour appliqué à chaque fabrique.
561 */
562 class IFactoryVisitorFunctor
563 {
564 public:
565 virtual ~IFactoryVisitorFunctor() = default;
566 virtual bool execute(impl::IInstanceFactory* f) = 0;
567 };
568
569 template <typename Lambda> class FactoryVisitorFunctor
570 : public IFactoryVisitorFunctor
571 {
572 public:
573 FactoryVisitorFunctor(Lambda& lambda)
574 : m_lambda(lambda)
575 {}
576
577 public:
578 virtual bool execute(impl::IInstanceFactory* f) { return m_lambda(f); }
579
580 private:
581 Lambda& m_lambda;
582 };
583
584 /*!
585 * \brief Interface d'un fonctor pour appliqué à chaque fabrique.
586 */
587 class IInstanceVisitorFunctor
588 {
589 public:
590 virtual ~IInstanceVisitorFunctor() = default;
591 virtual bool execute(IInjectedInstance* v) = 0;
592 };
593
594 template <typename Lambda> class InstanceVisitorFunctor
595 : public IInstanceVisitorFunctor
596 {
597 public:
598 InstanceVisitorFunctor(Lambda& lambda)
599 : m_lambda(lambda)
600 {}
601
602 public:
603 virtual bool execute(IInjectedInstance* v) { return m_lambda(v); }
604
605 private:
606 Lambda& m_lambda;
607 };
608
609 public:
610 Injector();
611 Injector(const Injector&) = delete;
612 Injector& operator=(const Injector&) = delete;
613 ~Injector();
614
615 public:
616 template <typename Type> void
617 bind(Type iref, const String& name = String())
618 {
619 _add(InjectorHelper<Type>::bind(iref, name));
620 }
621
622 template <typename Type> Type
623 get(const String& name = String())
624 {
625 return InjectorHelper<Type>::get(*this, name);
626 }
627
628 template <typename InterfaceType> Ref<InterfaceType>
629 createInstance(const String& service_name = String())
630 {
631 using FactoryType = impl::InstanceFactory<InterfaceType>;
632 Ref<InterfaceType> instance;
633 auto f = [&](impl::IInstanceFactory* v) -> bool {
634 auto* t = dynamic_cast<FactoryType*>(v);
635 //std::cout << "TRY DYNAMIC_CAST FACTORY v=" << v << " t=" << t << "\n";
636 if (t) {
637 Ref<InterfaceType> x = t->createReference(*this);
638 if (x.get()) {
639 instance = x;
640 return true;
641 }
642 }
643 return false;
644 };
645 FactoryVisitorFunctor ff(f);
646 _iterateFactories(service_name, &ff);
647 if (instance.get())
648 return instance;
649 // TODO: améliorer le message
650 _doError(A_FUNCINFO, "Can not create instance");
651 }
652
653 String printFactories() const;
654
655 void fillWithGlobalFactories();
656
657 private:
658 Impl* m_p = nullptr;
659
660 private:
661 void _add(IInjectedInstance* instance);
662
663 // Itère sur la lambda et s'arrête dès que cette dernière retourne \a true
664 void _iterateInstances(const std::type_info& t_info, const String& instance_name,
665 IInstanceVisitorFunctor* lambda);
666 Integer _nbValue() const;
667 IInjectedInstance* _value(Integer i) const;
668
669 /*!
670 * \brief Itère sur les fabriques et applique le fonctor \a functor.
671 *
672 * On s'arrête dès qu'un appel à functor retourne \a true.
673 *
674 * Si \a factory_name n'est pas nul, seules les fabriques pour lequelles
675 * FactoryInfo::hasName(factory_name) est vrai sont utilisées.
676 */
677 void _iterateFactories(const String& factory_name, IFactoryVisitorFunctor* functor) const;
678 Integer _nbFactory() const;
679 impl::IInstanceFactory* _factory(Integer i) const;
680
681 // Spécialisation pour les références
682 template <typename InterfaceType> Ref<InterfaceType>
683 _getRef(const String& instance_name)
684 {
685 using InjectedType = impl::IInjectedRefInstanceT<InterfaceType>;
686 InjectedType* t = nullptr;
687 auto f = [&](IInjectedInstance* v) -> bool {
688 t = dynamic_cast<InjectedType*>(v);
689 return t;
690 };
691 InstanceVisitorFunctor ff(f);
692 _iterateInstances(typeid(Ref<InterfaceType>), instance_name, &ff);
693 if (t)
694 return t->instance();
695 // TODO: faire un fatal ou créer l'instance
696 ARCANE_THROW(NotImplementedException, "Create Ref<InterfaceType> from factory");
697 }
698
699 template <typename Type> Type
700 _getValue(const String& instance_name)
701 {
702 using InjectedType = impl::IInjectedValueInstance<Type>;
703 InjectedType* t = nullptr;
704 auto f = [&](IInjectedInstance* v) -> bool {
705 t = dynamic_cast<InjectedType*>(v);
706 return t;
707 };
708 InstanceVisitorFunctor ff(f);
709 _iterateInstances(typeid(Type), instance_name, &ff);
710 if (t)
711 return t->instance();
712 _doError(A_FUNCINFO, "Can not find value for type");
713 }
714 [[noreturn]] void _doError(const TraceInfo& ti, const String& message);
715};
716
717/*---------------------------------------------------------------------------*/
718/*---------------------------------------------------------------------------*/
719
720} // namespace Arcane::DependencyInjection
721
722namespace Arcane::DependencyInjection::impl
723{
724
725/*---------------------------------------------------------------------------*/
726/*---------------------------------------------------------------------------*/
727
728class ARCANE_UTILS_EXPORT ConstructorRegistererBase
729{
730 protected:
731 [[noreturn]] void _doError1(const String& message, int nb_value);
732};
733
734/*!
735 * \internal
736 * \brief Classe permettant d'enregistrer un constructeur pour créer un objet
737 * via un Injector.
738 * \a ConstructorArgsType est un `std::tuple` des arguments du constructeur
739 */
740template <typename... Args>
741class ConstructorRegisterer
742: public ConstructorRegistererBase
743{
744 public:
745 using ArgsType = std::tuple<Args...>;
746
747 ConstructorRegisterer() {}
748
749 // Permet de récupérer via l'injecteur \a i le I-ème argument du tuple.
750 template <std::size_t I>
751 static auto _get(Injector& i) -> std::tuple_element_t<I, ArgsType>
752 {
753 using SelectedType = std::tuple_element_t<I, ArgsType>;
754 //std::cout << "RETURN _GET(I=" << I << ")\n";
755 return i.get<SelectedType>();
756 }
757
758 ArgsType createTuple(Injector& i)
759 {
760 // TODO: supporter plus d'arguments ou passer à des 'variadic templates'
761 constexpr int tuple_size = std::tuple_size<ArgsType>();
762 static_assert(tuple_size < 3, "Too many arguments for createTuple (max=2)");
763 if constexpr (tuple_size == 0) {
764 return ArgsType();
765 }
766 else if constexpr (tuple_size == 1) {
767 return ArgsType(_get<0>(i));
768 }
769 else if constexpr (tuple_size == 2) {
770 return ArgsType(_get<0>(i), _get<1>(i));
771 }
772 // Ne devrait pas arriver mais on ne sais jamais.
773 _doError1("Too many arguments for createTuple n={0} max=2", tuple_size);
774 }
775};
776
777/*---------------------------------------------------------------------------*/
778/*---------------------------------------------------------------------------*/
779/*!
780 * \internal
781 * \brief Fabrique pour le type \a ConcreteType pour l'interface \a InterfaceType
782 * via le constructeur \a ConstructorType.
783 */
784template <typename InterfaceType, typename ConcreteType, typename ConstructorType>
785class ConcreteFactory
786: public IConcreteFactory<InterfaceType>
787{
788 using Args = typename ConstructorType::ArgsType;
789
790 public:
791 Ref<InterfaceType> createReference(Injector& injector) override
792 {
793 ConstructorType ct;
794 ConcreteType* st = _create(ct.createTuple(injector));
795 return makeRef<InterfaceType>(st);
796 }
797 ConcreteFactoryTypeInfo concreteFactoryInfo() const override
798 {
799 return ConcreteFactoryTypeInfo::create<InterfaceType, ConcreteType, ConstructorType>();
800 }
801 Int32 nbConstructorArg() const override
802 {
803 return std::tuple_size<Args>();
804 }
805
806 private:
807 /*!
808 * Créé une instance du service à partir des arguments sous forme d'un std::tuple.
809 *
810 * \todo Regarder si on ne peut pas utiliser std::make_from_tuple()
811 */
812 ConcreteType* _create(const Args&& tuple_args)
813 {
814 ConcreteType* st = std::apply([](auto&&... args) -> ConcreteType* { return new ConcreteType(args...); }, tuple_args);
815 return st;
816 }
817};
818
819/*---------------------------------------------------------------------------*/
820/*---------------------------------------------------------------------------*/
821/*!
822 * \internal
823 * \brief Classe permettant d'enregistrer la liste des interfaces d'un service.
824 * \a Interfaces contient la liste des interfaces implémentées par le service
825 */
826template <typename... Interfaces>
827class InterfaceListRegisterer
828{
829 public:
830 /*!
831 * \brief Enregistre une fabrique.
832 *
833 * Enregistre pour chaque interface de \a Interfaces une fabrique pour
834 * créer une instance de \a ConcreteType via le constructeur \a ConstructorType
835 */
836 template <typename ConcreteType, typename ConstructorType> void
837 registerFactory(FactoryInfo* si)
838 {
839 _registerFactory<ConcreteType, ConstructorType, Interfaces...>(si);
840 }
841
842 private:
843 template <typename ConcreteType, typename ConstructorType,
844 typename InterfaceType, typename... OtherInterfaces>
845 void
846 _registerFactory(FactoryInfo* fi)
847 {
848 auto* factory = new ConcreteFactory<InterfaceType, ConcreteType, ConstructorType>();
849 fi->addFactory(createRef<InstanceFactory<InterfaceType>>(fi, factory));
850 // Applique récursivement pour les autres interfaces si nécessaire
851 if constexpr (sizeof...(OtherInterfaces) > 0)
852 _registerFactory<ConcreteType, ConstructorType, OtherInterfaces...>(fi);
853 }
854};
855
856/*---------------------------------------------------------------------------*/
857/*---------------------------------------------------------------------------*/
858/*!
859 * \internal
860 * \brief Classe permettant d'enregistrer des constructeurs pour créer un
861 * type \a ConcreteType implémentant les interfaces de \a InterfaceList (qui
862 * doit être du type InterfaceListRegisterer).
863 */
864template <typename ConcreteType, typename InterfaceList>
865class InjectionRegisterer
866{
867 public:
868 //! Enregistre dans \a si les fabriques correspondentes aux constructeurs \a Constructors
869 template <typename... Constructors> void
870 registerProviderInfo(FactoryInfo* si, const Constructors&... args)
871 {
872 _create(si, args...);
873 }
874
875 private:
876 // TODO: Créér l'instance de 'FactoryInfo' dans le constructeur
877 InterfaceList m_interface_list;
878
879 private:
880 //! Surcharge pour 1 constructeur
881 template <typename ConstructorType> void
882 _create(FactoryInfo* si, const ConstructorType&)
883 {
884 m_interface_list.template registerFactory<ConcreteType, ConstructorType>(si);
885 }
886
887 //! Surcharge pour 2 constructeurs ou plus
888 template <typename C1, typename C2, typename... OtherConstructors>
889 void _create(FactoryInfo* si, const C1& c1, const C2& c2, const OtherConstructors&... args)
890 {
891 _create<C1>(si, c1);
892 // Applique la récursivité sur les types restants
893 _create<C2, OtherConstructors...>(si, c2, args...);
894 }
895};
896
897/*---------------------------------------------------------------------------*/
898/*---------------------------------------------------------------------------*/
899
900} // End namespace Arcane::DependencyInjection::impl
901
902/*---------------------------------------------------------------------------*/
903/*---------------------------------------------------------------------------*/
904
905#define ARCANE_DI_CONSTRUCTOR(...) \
906 ::Arcane::DependencyInjection::impl::ConstructorRegisterer<__VA_ARGS__>()
907
908#define ARCANE_DI_EMPTY_CONSTRUCTOR(...) \
909 ::Arcane::DependencyInjection::impl::ConstructorRegisterer<>()
910
911// TODO: garantir au moins une interface
912
913#define ARCANE_DI_INTERFACES(...) \
914 ::Arcane::DependencyInjection::impl::InterfaceListRegisterer<__VA_ARGS__>
915
916#define ARCANE_DI_REGISTER_PROVIDER(t_class, t_provider_property, t_interfaces, ...) \
917 namespace \
918 { \
919 Arcane::DependencyInjection::impl::FactoryInfo* \
920 ARCANE_JOIN_WITH_LINE(arcaneCreateDependencyInjectionProviderInfo##t_class)(const Arcane::DependencyInjection::ProviderProperty& property) \
921 { \
922 auto* si = Arcane::DependencyInjection::impl::FactoryInfo::create(property, __FILE__, __LINE__); \
923 Arcane::DependencyInjection::impl::InjectionRegisterer<t_class, t_interfaces> injection_registerer; \
924 injection_registerer.registerProviderInfo(si, __VA_ARGS__); \
925 return si; \
926 } \
927 } \
928 Arcane::DependencyInjection::impl::GlobalRegisterer ARCANE_EXPORT ARCANE_JOIN_WITH_LINE(globalServiceRegisterer##aclass)(&ARCANE_JOIN_WITH_LINE(arcaneCreateDependencyInjectionProviderInfo##t_class), t_provider_property)
929
930/*---------------------------------------------------------------------------*/
931/*---------------------------------------------------------------------------*/
932
933#endif
#define ARCANE_THROW(exception_class,...)
Macro pour envoyer une exception avec formattage.
#define ARCCORE_DECLARE_REFERENCE_COUNTED_INCLASS_METHODS()
Macro pour déclarer les méthodes virtuelles gérant les compteurs de référence.
#define ARCCORE_DECLARE_REFERENCE_COUNTED_CLASS(class_name)
Macro pour déclarer qu'une classe utilise un compteur de référence.
#define ARCCORE_DEFINE_REFERENCE_COUNTED_INCLASS_METHODS()
Macro pour définir les méthodes gérant les compteurs de référence.
Chaîne de caractères unicode.
Int32 Integer
Type représentant un entier.