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