Arcane  v3.15.3.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-2025 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-2025 */
9/* */
10/* Types et fonctions pour gérer le pattern 'DependencyInjection'. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/utils/internal/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:
32
34 {
35 public:
36
37 InstanceInfo(IInjectedInstance* instance, Int32 index)
38 : m_instance(instance)
39 , m_index(index)
40 {}
41
42 public:
43
44 IInjectedInstance* m_instance = nullptr;
45 Int32 m_index = 0;
46 };
47
48 public:
49
50 ~Impl()
51 {
52 for (Integer i = 0, n = m_instance_list.size(); i < n; ++i)
53 delete m_instance_list[i].m_instance;
54 m_instance_list.clear();
55 }
56
57 public:
58
59 void addInstance(IInjectedInstance* instance)
60 {
61 Int32 index = m_instance_list.size();
62 m_instance_list.add(InstanceInfo{ instance, index });
63 }
64 IInjectedInstance* instance(Int32 index) const { return m_instance_list[index].m_instance; }
65 Int32 nbInstance() const { return m_instance_list.size(); }
66
67 private:
68
69 UniqueArray<InstanceInfo> m_instance_list;
70
71 public:
72
73 // Il faut conserver une instance de FactoryInfo pour éviter sa
74 // destruction prématurée car les instances dans m_factories en ont besoin.
75 UniqueArray<Ref<impl::IInstanceFactory>> m_factories;
76 UniqueArray<impl::FactoryInfo> m_factories_info;
77};
78
79/*---------------------------------------------------------------------------*/
80/*---------------------------------------------------------------------------*/
81
82Injector::
83Injector()
84: m_p(new Impl())
85{
86}
87
88/*---------------------------------------------------------------------------*/
89/*---------------------------------------------------------------------------*/
90
91Injector::
92~Injector()
93{
94 delete m_p;
95}
96
97/*---------------------------------------------------------------------------*/
98/*---------------------------------------------------------------------------*/
99
100void Injector::
101_add(IInjectedInstance* instance)
102{
103 m_p->addInstance(instance);
104}
105
106/*---------------------------------------------------------------------------*/
107/*---------------------------------------------------------------------------*/
108
109Integer Injector::
110_nbValue() const
111{
112 return m_p->nbInstance();
113}
114
115/*---------------------------------------------------------------------------*/
116/*---------------------------------------------------------------------------*/
117
118IInjectedInstance* Injector::
119_value(Integer i) const
120{
121 return m_p->instance(i);
122}
123
124/*---------------------------------------------------------------------------*/
125/*---------------------------------------------------------------------------*/
126
127Integer Injector::
128_nbFactory() const
129{
130 return m_p->m_factories.size();
131}
132
133/*---------------------------------------------------------------------------*/
134/*---------------------------------------------------------------------------*/
135
136impl::IInstanceFactory* Injector::
137_factory(Integer i) const
138{
139 return m_p->m_factories[i].get();
140}
141
142/*---------------------------------------------------------------------------*/
143/*---------------------------------------------------------------------------*/
144
145}
146
147/*---------------------------------------------------------------------------*/
148/*---------------------------------------------------------------------------*/
149
150namespace Arcane::DependencyInjection::impl
151{
152
153/*---------------------------------------------------------------------------*/
154/*---------------------------------------------------------------------------*/
155
156void ConstructorRegistererBase::
157_doError1(const String& message, int nb_value)
158{
159 ARCANE_FATAL(message,nb_value);
160}
161
162/*---------------------------------------------------------------------------*/
163/*---------------------------------------------------------------------------*/
164
166{
167 public:
168
169 FactoryInfoImpl(const ProviderProperty& property)
170 : m_property(property)
171 , m_name(property.name())
172 {
173 }
174
175 public:
176
177 bool hasName(const String& str) const { return str == m_name; }
178 void fillWithImplementationNames(Array<String>& names) const { names.add(m_name); }
179
180 public:
181
182 const ProviderProperty m_property;
184 String m_name;
185};
186
187/*---------------------------------------------------------------------------*/
188/*---------------------------------------------------------------------------*/
189
190FactoryInfo::
191FactoryInfo(const ProviderProperty& property)
192: m_p(std::make_shared<FactoryInfoImpl>(property))
193{
194}
195
196/*---------------------------------------------------------------------------*/
197/*---------------------------------------------------------------------------*/
198
199void FactoryInfo::
200addFactory(Ref<IInstanceFactory> f)
201{
202 m_p->m_factories.add(f);
203}
204
205/*---------------------------------------------------------------------------*/
206/*---------------------------------------------------------------------------*/
207
208bool FactoryInfo::
209hasName(const String& str) const
210{
211 return m_p->hasName(str);
212}
213
214/*---------------------------------------------------------------------------*/
215/*---------------------------------------------------------------------------*/
216
217/*---------------------------------------------------------------------------*/
218/*---------------------------------------------------------------------------*/
219
220GlobalRegisterer::
221GlobalRegisterer(FactoryCreateFunc func, const ProviderProperty& property) noexcept
222: m_factory_create_func(func)
223, m_factory_property(property)
224{
225}
226
227/*---------------------------------------------------------------------------*/
228/*---------------------------------------------------------------------------*/
229
230GenericRegisterer<GlobalRegisterer>::Info GlobalRegisterer::m_global_registerer_info;
231
232/*---------------------------------------------------------------------------*/
233/*---------------------------------------------------------------------------*/
234
235} // End namespace impl
236
237namespace Arcane::DependencyInjection
238{
239
240/*---------------------------------------------------------------------------*/
241/*---------------------------------------------------------------------------*/
242
243void Injector::
244fillWithGlobalFactories()
245{
246 impl::GlobalRegisterer* g = impl::GlobalRegisterer::firstRegisterer();
247 Integer i = 0;
248 while (g) {
249 auto func = g->infoCreatorWithPropertyFunction();
250 if (func) {
251 impl::FactoryInfo fi = (*func)(g->property());
252 m_p->m_factories_info.add(fi);
253 m_p->m_factories.addRange(fi.m_p->m_factories);
254 }
255
256 g = g->nextRegisterer();
257 ++i;
258 if (i > 100000)
259 ARCANE_FATAL("Infinite loop in DependencyInjection global factories");
260 }
261}
262
263/*---------------------------------------------------------------------------*/
264/*---------------------------------------------------------------------------*/
265
266String Injector::
267printFactories() const
268{
269 std::ostringstream ostr;
270 Integer index = 0;
271 auto f = [&](impl::IInstanceFactory* v) -> bool {
272 const impl::ConcreteFactoryTypeInfo& cfi = v->concreteFactoryInfo();
273 ostr << "I=" << index << " " << typeid(v).name()
274 << "\n interface=" << cfi.interfaceTypeInfo().traceInfo()
275 << "\n concrete=" << cfi.concreteTypeInfo().traceInfo()
276 << "\n constructor=" << cfi.constructorTypeInfo().traceInfo()
277 << "\n";
278 ++index;
279 return false;
280 };
281 FactoryVisitorFunctor ff(f);
282 _iterateFactories(String(), &ff);
283 String s = ostr.str();
284 return s;
285}
286
287/*---------------------------------------------------------------------------*/
288/*---------------------------------------------------------------------------*/
289
290void Injector::
291_iterateFactories(const String& factory_name, IFactoryVisitorFunctor* functor) const
292{
293 // TODO: utiliser le std::type_info de l'instance qu'on souhaite pour limiter
294 // les itérations
295
296 // Il faut trouver un constructeur qui ait le même nombre d'arguments
297 // que le nombre d'instances enregistrées
298 bool has_no_name = factory_name.empty();
299 Integer n = _nbFactory();
300 Integer nb_instance = _nbValue();
301 for (Integer i = 0; i < n; ++i) {
302 impl::IInstanceFactory* f = _factory(i);
303 Int32 nb_constructor_arg = f->nbConstructorArg();
304 if (nb_constructor_arg >= 0 && nb_constructor_arg != nb_instance)
305 continue;
306 if (has_no_name || f->factoryInfoImpl()->hasName(factory_name)) {
307 if (functor->execute(f))
308 return;
309 }
310 }
311}
312
313/*---------------------------------------------------------------------------*/
314/*---------------------------------------------------------------------------*/
315
316// Itère sur la lambda et s'arrête dès que cette dernière retourne \a true
317void Injector::
318_iterateInstances(const std::type_info& t_info, const String& instance_name,
319 IInstanceVisitorFunctor* lambda)
320{
321 bool has_no_name = instance_name.empty();
322 Integer n = _nbValue();
323 for (Integer i = 0; i < n; ++i) {
324 IInjectedInstance* ii = _value(i);
325 if (!ii->hasTypeInfo(t_info))
326 continue;
327 if (has_no_name || ii->hasName(instance_name)) {
328 if (lambda->execute(ii))
329 return;
330 }
331 }
332}
333
334/*---------------------------------------------------------------------------*/
335/*---------------------------------------------------------------------------*/
336
337void Injector::
338_doError(const TraceInfo& ti, const String& message)
339{
340 ARCANE_FATAL("Function: {0} : {1}", ti, message);
341}
342
343/*---------------------------------------------------------------------------*/
344/*---------------------------------------------------------------------------*/
345
346void Injector::
347_printValidImplementationAndThrow(const TraceInfo& ti,
348 const String& implementation_name,
349 FactoryFilterFunc filter_func)
350{
351 // Pas d'implémentation correspondante trouvée.
352 // Dans ce cas on récupère la liste des implémentations valides et on les affiche dans
353 // le message d'erreur.
354 UniqueArray<String> valid_names;
355 for (Int32 i = 0, n = _nbFactory(); i < n; ++i) {
356 impl::IInstanceFactory* f = _factory(i);
357 if (filter_func(f)) {
358 f->factoryInfoImpl()->fillWithImplementationNames(valid_names);
359 }
360 };
361 String message = String::format("No implementation named '{0}' found", implementation_name);
362
363 // TODO: améliorer le message
364 String message2;
365 if (valid_names.size() == 0)
366 message2 = " and no implementation is available.";
367 else if (valid_names.size() == 1)
368 message2 = String::format(". Valid value is: '{0}'.", valid_names[0]);
369 else
370 message2 = String::format(". Valid values are: '{0}'.", String::join(", ", valid_names));
371 _doError(ti, message + message2);
372}
373
374/*---------------------------------------------------------------------------*/
375/*---------------------------------------------------------------------------*/
376
377} // namespace Arcane::DependencyInjection
378
379/*---------------------------------------------------------------------------*/
380/*---------------------------------------------------------------------------*/
381
382namespace Arccore
383{
384ARCCORE_DEFINE_REFERENCE_COUNTED_CLASS(Arcane::DependencyInjection::impl::IInstanceFactory);
385}
386
387/*---------------------------------------------------------------------------*/
388/*---------------------------------------------------------------------------*/
#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.
Référence à une instance.
Chaîne de caractères unicode.
Espace de nom de Arccore.
Definition ArcaneTypes.h:29
Int32 Integer
Type représentant un entier.