Arcane  v3.14.11.0
Documentation utilisateur
Chargement...
Recherche...
Aucune correspondance
DependencyInjection.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2022 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.cc (C) 2000-2021 */
9/* */
10/* Types et fonctions pour gérer le pattern 'DependencyInjection'. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/utils/DependencyInjection.h"
15
16#include "arcane/utils/UniqueArray.h"
17#include "arcane/utils/ExternalRef.h"
18#include "arcane/utils/FatalErrorException.h"
19
20/*---------------------------------------------------------------------------*/
21/*---------------------------------------------------------------------------*/
22
23namespace Arcane::DependencyInjection
24{
25
26/*---------------------------------------------------------------------------*/
27/*---------------------------------------------------------------------------*/
28
30{
31 public:
33 {
34 public:
35 InstanceInfo(IInjectedInstance* instance, Int32 index)
36 : m_instance(instance)
37 , m_index(index)
38 {}
39
40 public:
41 IInjectedInstance* m_instance = nullptr;
42 Int32 m_index = 0;
43 };
44
45 public:
46 ~Impl()
47 {
48 for (Integer i = 0, n = m_instance_list.size(); i < n; ++i)
49 delete m_instance_list[i].m_instance;
50 m_instance_list.clear();
51 }
52
53 public:
54 void addInstance(IInjectedInstance* instance)
55 {
56 Int32 index = m_instance_list.size();
57 m_instance_list.add(InstanceInfo{ instance, index });
58 }
59 IInjectedInstance* instance(Int32 index) const { return m_instance_list[index].m_instance; }
60 Int32 nbInstance() const { return m_instance_list.size(); }
61
62 private:
63 UniqueArray<InstanceInfo> m_instance_list;
64
65 public:
66 UniqueArray<Ref<impl::IInstanceFactory>> m_factories;
67};
68
69/*---------------------------------------------------------------------------*/
70/*---------------------------------------------------------------------------*/
71
72Injector::
73Injector()
74: m_p(new Impl())
75{
76}
77
78/*---------------------------------------------------------------------------*/
79/*---------------------------------------------------------------------------*/
80
81Injector::
82~Injector()
83{
84 delete m_p;
85}
86
87/*---------------------------------------------------------------------------*/
88/*---------------------------------------------------------------------------*/
89
90void Injector::
91_add(IInjectedInstance* instance)
92{
93 m_p->addInstance(instance);
94}
95
96/*---------------------------------------------------------------------------*/
97/*---------------------------------------------------------------------------*/
98
99Integer Injector::
100_nbValue() const
101{
102 return m_p->nbInstance();
103}
104
105/*---------------------------------------------------------------------------*/
106/*---------------------------------------------------------------------------*/
107
108IInjectedInstance* Injector::
109_value(Integer i) const
110{
111 return m_p->instance(i);
112}
113
114/*---------------------------------------------------------------------------*/
115/*---------------------------------------------------------------------------*/
116
117Integer Injector::
118_nbFactory() const
119{
120 return m_p->m_factories.size();
121}
122
123/*---------------------------------------------------------------------------*/
124/*---------------------------------------------------------------------------*/
125
126impl::IInstanceFactory* Injector::
127_factory(Integer i) const
128{
129 return m_p->m_factories[i].get();
130}
131
132/*---------------------------------------------------------------------------*/
133/*---------------------------------------------------------------------------*/
134
135}
136
137/*---------------------------------------------------------------------------*/
138/*---------------------------------------------------------------------------*/
139
140namespace Arcane::DependencyInjection::impl
141{
142
143/*---------------------------------------------------------------------------*/
144/*---------------------------------------------------------------------------*/
145
146void ConstructorRegistererBase::
147_doError1(const String& message, int nb_value)
148{
149 ARCANE_FATAL(message,nb_value);
150}
151
152/*---------------------------------------------------------------------------*/
153/*---------------------------------------------------------------------------*/
154
156{
157 public:
158 Impl(const ProviderProperty& property)
159 : m_property(property)
160 , m_name(property.name())
161 {
162 }
163
164 public:
165 const ProviderProperty m_property;
167 String m_name;
168};
169
170/*---------------------------------------------------------------------------*/
171/*---------------------------------------------------------------------------*/
172
173FactoryInfo::
174FactoryInfo(const ProviderProperty& property)
175: m_p{ new Impl(property) }
176{
177}
178
179/*---------------------------------------------------------------------------*/
180/*---------------------------------------------------------------------------*/
181
182FactoryInfo::
183~FactoryInfo()
184{
185 delete m_p;
186}
187
188/*---------------------------------------------------------------------------*/
189/*---------------------------------------------------------------------------*/
190
191void FactoryInfo::
192addFactory(Ref<IInstanceFactory> f)
193{
194 m_p->m_factories.add(f);
195}
196
197/*---------------------------------------------------------------------------*/
198/*---------------------------------------------------------------------------*/
199
200bool FactoryInfo::
201hasName(const String& str) const
202{
203 return str == m_p->m_name;
204}
205
206/*---------------------------------------------------------------------------*/
207/*---------------------------------------------------------------------------*/
208
209/*---------------------------------------------------------------------------*/
210/*---------------------------------------------------------------------------*/
211
212GlobalRegisterer::
213GlobalRegisterer(FactoryCreateFunc func, const ProviderProperty& property) noexcept
214: m_factory_create_func(func)
215, m_factory_property(property)
216{
217}
218
219/*---------------------------------------------------------------------------*/
220/*---------------------------------------------------------------------------*/
221
222GenericRegisterer<GlobalRegisterer>::Info GlobalRegisterer::m_global_registerer_info;
223
224/*---------------------------------------------------------------------------*/
225/*---------------------------------------------------------------------------*/
226
227} // End namespace impl
228
229namespace Arcane::DependencyInjection
230{
231
232/*---------------------------------------------------------------------------*/
233/*---------------------------------------------------------------------------*/
234
235void Injector::
236fillWithGlobalFactories()
237{
238 impl::GlobalRegisterer* g = impl::GlobalRegisterer::firstRegisterer();
239 Integer i = 0;
240 while (g) {
241 auto func = g->infoCreatorWithPropertyFunction();
242 impl::FactoryInfo* fi = nullptr;
243 if (func)
244 fi = (*func)(g->property());
245 if (fi)
246 m_p->m_factories.addRange(fi->m_p->m_factories);
247
248 g = g->nextRegisterer();
249 ++i;
250 if (i > 100000)
251 ARCANE_FATAL("Infinite loop in DependencyInjection global factories");
252 }
253}
254
255/*---------------------------------------------------------------------------*/
256/*---------------------------------------------------------------------------*/
257
258String Injector::
259printFactories() const
260{
261 std::ostringstream ostr;
262 Integer index = 0;
263 auto f = [&](impl::IInstanceFactory* v) -> bool {
264 const impl::ConcreteFactoryTypeInfo& cfi = v->concreteFactoryInfo();
265 ostr << "I=" << index << " " << typeid(v).name()
266 << "\n interface=" << cfi.interfaceTypeInfo().traceInfo()
267 << "\n concrete=" << cfi.concreteTypeInfo().traceInfo()
268 << "\n constructor=" << cfi.constructorTypeInfo().traceInfo()
269 << "\n";
270 ++index;
271 return false;
272 };
273 FactoryVisitorFunctor ff(f);
274 _iterateFactories(String(), &ff);
275 String s = ostr.str();
276 return s;
277}
278
279/*---------------------------------------------------------------------------*/
280/*---------------------------------------------------------------------------*/
281
282void Injector::
283_iterateFactories(const String& factory_name, IFactoryVisitorFunctor* functor) const
284{
285 // TODO: utiliser le std::type_info de l'instance qu'on souhaite pour limiter
286 // les itérations
287
288 // Il faut trouver un constructeur qui ait le même nombre d'arguments
289 // que le nombre d'instances enregistrées
290 bool has_no_name = factory_name.empty();
291 Integer n = _nbFactory();
292 Integer nb_instance = _nbValue();
293 for (Integer i = 0; i < n; ++i) {
294 impl::IInstanceFactory* f = _factory(i);
295 Int32 nb_constructor_arg = f->nbConstructorArg();
296 if (nb_constructor_arg >= 0 && nb_constructor_arg != nb_instance)
297 continue;
298 if (has_no_name || f->factoryInfo()->hasName(factory_name)) {
299 if (functor->execute(f))
300 return;
301 }
302 }
303}
304
305/*---------------------------------------------------------------------------*/
306/*---------------------------------------------------------------------------*/
307
308// Itère sur la lambda et s'arrête dès que cette dernière retourne \a true
309void Injector::
310_iterateInstances(const std::type_info& t_info, const String& instance_name,
311 IInstanceVisitorFunctor* lambda)
312{
313 bool has_no_name = instance_name.empty();
314 Integer n = _nbValue();
315 for (Integer i = 0; i < n; ++i) {
316 IInjectedInstance* ii = _value(i);
317 if (!ii->hasTypeInfo(t_info))
318 continue;
319 if (has_no_name || ii->hasName(instance_name)) {
320 if (lambda->execute(ii))
321 return;
322 }
323 }
324}
325
326/*---------------------------------------------------------------------------*/
327/*---------------------------------------------------------------------------*/
328
329void Injector::
330_doError(const TraceInfo& ti, const String& message)
331{
332 ARCANE_FATAL("Function: {0} : {1}", ti, message);
333}
334
335/*---------------------------------------------------------------------------*/
336/*---------------------------------------------------------------------------*/
337
338} // namespace Arcane::DependencyInjection
339
340/*---------------------------------------------------------------------------*/
341/*---------------------------------------------------------------------------*/
342
343namespace Arccore
344{
345ARCCORE_DEFINE_REFERENCE_COUNTED_CLASS(Arcane::DependencyInjection::impl::IInstanceFactory);
346}
347
348/*---------------------------------------------------------------------------*/
349/*---------------------------------------------------------------------------*/
#define ARCANE_FATAL(...)
Macro envoyant une exception FatalErrorException.
#define ARCCORE_DEFINE_REFERENCE_COUNTED_CLASS(class_name)
Macro pour définir les méthodes et types une classe qui utilise un compteur de référence.
void add(ConstReferenceType val)
Ajoute l'élément val à la fin du tableau.
Chaîne de caractères unicode.
Vecteur 1D de données avec sémantique par valeur (style STL).
Espace de nom de Arccore.
Definition ArcaneTypes.h:24
Int32 Integer
Type représentant un entier.