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