Ginkgo  Generated from pipelines/2662685947 branch based on develop. Ginkgo version 2.0.0
A numerical linear algebra library targeting many-core architectures
abstract_factory.hpp
1 // SPDX-FileCopyrightText: 2017 - 2026 The Ginkgo authors
2 //
3 // SPDX-License-Identifier: BSD-3-Clause
4 
5 #ifndef GKO_PUBLIC_CORE_BASE_ABSTRACT_FACTORY_HPP_
6 #define GKO_PUBLIC_CORE_BASE_ABSTRACT_FACTORY_HPP_
7 
8 
9 #include <type_traits>
10 #include <unordered_map>
11 
12 #include <ginkgo/core/base/polymorphic_object.hpp>
13 
14 
20 namespace gko {
21 
22 
44 template <typename AbstractProductType, typename ComponentsType>
46 public:
47  using abstract_product_type = AbstractProductType;
48  using components_type = ComponentsType;
49 
64  template <typename... Args>
65  std::unique_ptr<abstract_product_type> generate(Args&&... args) const
66  {
67  auto product =
68  this->generate_impl(components_type{std::forward<Args>(args)...});
69  for (auto logger : this->loggers_) {
70  product->add_logger(logger);
71  }
72  return product;
73  }
74 
75 protected:
81  AbstractFactory(std::shared_ptr<const Executor> exec)
82  : PolymorphicObject(std::move(exec))
83  {}
84 
92  virtual std::unique_ptr<abstract_product_type> generate_impl(
93  ComponentsType args) const = 0;
94 };
95 
96 
120 template <typename ConcreteFactory, typename ProductType,
121  typename ParametersType, typename PolymorphicBase>
122 class EnableDefaultFactory : public PolymorphicBase {
123 public:
124  using product_type = ProductType;
125  using parameters_type = ParametersType;
126  using polymorphic_base = PolymorphicBase;
127  using abstract_product_type =
128  typename PolymorphicBase::abstract_product_type;
129  using components_type = typename PolymorphicBase::components_type;
130 
131  template <typename... Args>
132  std::unique_ptr<product_type> generate(Args&&... args) const
133  {
134  auto product = std::unique_ptr<product_type>(static_cast<product_type*>(
135  this->polymorphic_base::generate(std::forward<Args>(args)...)
136  .release()));
137  return product;
138  }
139 
145  const parameters_type& get_parameters() const noexcept
146  {
147  return parameters_;
148  };
149 
162  static parameters_type create() { return {}; }
163 
164 protected:
171  explicit EnableDefaultFactory(std::shared_ptr<const Executor> exec,
172  const parameters_type& parameters = {})
173  : PolymorphicBase(std::move(exec)), parameters_{parameters}
174  {}
175 
176  std::unique_ptr<abstract_product_type> generate_impl(
177  components_type args) const override
178  {
179  return std::unique_ptr<abstract_product_type>(
180  new product_type(self(), args));
181  }
182 
183 private:
184  GKO_ENABLE_SELF(ConcreteFactory);
185 
186  ParametersType parameters_;
187 };
188 
189 
202 template <typename ConcreteParametersType, typename Factory>
204 public:
205  using factory = Factory;
206 
211  template <typename... Args>
212  ConcreteParametersType& with_loggers(Args&&... _value)
213  {
214  this->loggers = {std::forward<Args>(_value)...};
215  return *self();
216  }
217 
225  std::unique_ptr<Factory> on(std::shared_ptr<const Executor> exec) const
226  {
227  ConcreteParametersType copy = *self();
228  for (const auto& item : deferred_factories) {
229  item.second(exec, copy);
230  }
231  auto factory = std::unique_ptr<Factory>(new Factory(exec, copy));
232  for (auto& logger : loggers) {
233  factory->add_logger(logger);
234  };
235  return factory;
236  }
237 
238 protected:
239  GKO_ENABLE_SELF(ConcreteParametersType);
240 
244  std::vector<std::shared_ptr<const log::Logger>> loggers{};
245 
252  std::unordered_map<std::string,
253  std::function<void(std::shared_ptr<const Executor> exec,
254  ConcreteParametersType&)>>
255  deferred_factories;
256 };
257 
258 
272 #define GKO_CREATE_FACTORY_PARAMETERS(_parameters_name, _factory_name) \
273 public: \
274  class _factory_name; \
275  struct _parameters_name##_type \
276  : public ::gko::enable_parameters_type<_parameters_name##_type, \
277  _factory_name>
278 
279 
280 namespace detail {
281 
282 
283 // Use pointer not the type because std::is_convertible<const type, type> can be
284 // true.
285 template <typename From, typename To>
286 struct is_pointer_convertible : std::is_convertible<From*, To*> {};
287 
288 
289 } // namespace detail
290 
291 
300 template <typename FactoryType>
302 public:
304  deferred_factory_parameter() = default;
305 
308  {
309  generator_ = [](std::shared_ptr<const Executor>) { return nullptr; };
310  }
311 
316  template <typename ConcreteFactoryType,
317  std::enable_if_t<detail::is_pointer_convertible<
318  ConcreteFactoryType, FactoryType>::value>* = nullptr>
319  deferred_factory_parameter(std::shared_ptr<ConcreteFactoryType> factory)
320  {
321  generator_ = [factory =
322  std::shared_ptr<FactoryType>(std::move(factory))](
323  std::shared_ptr<const Executor>) { return factory; };
324  }
325 
330  template <typename ConcreteFactoryType, typename Deleter,
331  std::enable_if_t<detail::is_pointer_convertible<
332  ConcreteFactoryType, FactoryType>::value>* = nullptr>
334  std::unique_ptr<ConcreteFactoryType, Deleter> factory)
335  {
336  generator_ = [factory =
337  std::shared_ptr<FactoryType>(std::move(factory))](
338  std::shared_ptr<const Executor>) { return factory; };
339  }
340 
346  template <typename ParametersType,
347  typename U = decltype(std::declval<ParametersType>().on(
348  std::shared_ptr<const Executor>{})),
349  std::enable_if_t<detail::is_pointer_convertible<
350  typename U::element_type, FactoryType>::value>* = nullptr>
351  deferred_factory_parameter(ParametersType parameters)
352  {
353  generator_ = [parameters](std::shared_ptr<const Executor> exec)
354  -> std::shared_ptr<FactoryType> { return parameters.on(exec); };
355  }
356 
361  std::shared_ptr<FactoryType> on(std::shared_ptr<const Executor> exec) const
362  {
363  if (this->is_empty()) {
364  GKO_NOT_SUPPORTED(*this);
365  }
366  return generator_(exec);
367  }
368 
370  bool is_empty() const { return !bool(generator_); }
371 
372 private:
373  std::function<std::shared_ptr<FactoryType>(std::shared_ptr<const Executor>)>
374  generator_;
375 };
376 
377 
386 #define GKO_ENABLE_BUILD_METHOD(_factory_name) \
387  static auto build()->decltype(_factory_name::create()) \
388  { \
389  return _factory_name::create(); \
390  } \
391  static_assert(true, \
392  "This assert is used to counter the false positive extra " \
393  "semi-colon warnings")
394 
395 
396 #if !(defined(__CUDACC__) || defined(__HIPCC__))
397 
409 #define GKO_FACTORY_PARAMETER(_name, ...) \
410  _name{__VA_ARGS__}; \
411  \
412  template <typename... Args> \
413  auto with_##_name(Args&&... _value) \
414  ->std::decay_t<decltype(*(this->self()))>& \
415  { \
416  using type = decltype(this->_name); \
417  this->_name = type{std::forward<Args>(_value)...}; \
418  return *(this->self()); \
419  } \
420  static_assert(true, \
421  "This assert is used to counter the false positive extra " \
422  "semi-colon warnings")
423 
437 #define GKO_FACTORY_PARAMETER_SCALAR(_name, _default) \
438  GKO_FACTORY_PARAMETER(_name, _default)
439 
453 #define GKO_FACTORY_PARAMETER_VECTOR(_name, ...) \
454  GKO_FACTORY_PARAMETER(_name, __VA_ARGS__)
455 #else // defined(__CUDACC__) || defined(__HIPCC__)
456 // A workaround for the NVCC compiler - parameter pack expansion does not work
457 // properly, because while the assignment to a scalar value is translated by
458 // cudafe into a C-style cast, the parameter pack expansion is not removed and
459 // `Args&&... args` is still kept as a parameter pack.
460 #define GKO_FACTORY_PARAMETER(_name, ...) \
461  _name{__VA_ARGS__}; \
462  \
463  template <typename... Args> \
464  auto with_##_name(Args&&... _value) \
465  ->std::decay_t<decltype(*(this->self()))>& \
466  { \
467  GKO_NOT_IMPLEMENTED; \
468  return *(this->self()); \
469  } \
470  static_assert(true, \
471  "This assert is used to counter the false positive extra " \
472  "semi-colon warnings")
473 
474 #define GKO_FACTORY_PARAMETER_SCALAR(_name, _default) \
475  _name{_default}; \
476  \
477  template <typename Arg> \
478  auto with_##_name(Arg&& _value)->std::decay_t<decltype(*(this->self()))>& \
479  { \
480  using type = decltype(this->_name); \
481  this->_name = type{std::forward<Arg>(_value)}; \
482  return *(this->self()); \
483  } \
484  static_assert(true, \
485  "This assert is used to counter the false positive extra " \
486  "semi-colon warnings")
487 
488 #define GKO_FACTORY_PARAMETER_VECTOR(_name, ...) \
489  _name{__VA_ARGS__}; \
490  \
491  template <typename... Args> \
492  auto with_##_name(Args&&... _value) \
493  ->std::decay_t<decltype(*(this->self()))>& \
494  { \
495  using type = decltype(this->_name); \
496  this->_name = type{std::forward<Args>(_value)...}; \
497  return *(this->self()); \
498  } \
499  static_assert(true, \
500  "This assert is used to counter the false positive extra " \
501  "semi-colon warnings")
502 #endif // defined(__CUDACC__) || defined(__HIPCC__)
503 
513 #define GKO_DEFERRED_FACTORY_PARAMETER(_name) \
514  _name{}; \
515  \
516 private: \
517  using _name##_type = typename decltype(_name)::element_type; \
518  \
519 public: \
520  auto with_##_name(::gko::deferred_factory_parameter<_name##_type> factory) \
521  ->std::decay_t<decltype(*(this->self()))>& \
522  { \
523  this->_name##_generator_ = std::move(factory); \
524  this->deferred_factories[#_name] = [](const auto& exec, \
525  auto& params) { \
526  if (!params._name##_generator_.is_empty()) { \
527  params._name = params._name##_generator_.on(exec); \
528  } \
529  }; \
530  return *(this->self()); \
531  } \
532  \
533 private: \
534  ::gko::deferred_factory_parameter<_name##_type> _name##_generator_; \
535  \
536 public: \
537  static_assert(true, \
538  "This assert is used to counter the false positive extra " \
539  "semi-colon warnings")
540 
551 #define GKO_DEFERRED_FACTORY_VECTOR_PARAMETER(_name) \
552  _name{}; \
553  \
554 private: \
555  using _name##_type = typename decltype(_name)::value_type::element_type; \
556  \
557 public: \
558  template <typename... Args, \
559  typename = std::enable_if_t<::std::conjunction< \
560  std::is_convertible<Args, ::gko::deferred_factory_parameter< \
561  _name##_type>>...>::value>> \
562  auto with_##_name(Args&&... factories) \
563  ->std::decay_t<decltype(*(this->self()))>& \
564  { \
565  this->_name##_generator_ = { \
566  ::gko::deferred_factory_parameter<_name##_type>{ \
567  std::forward<Args>(factories)}...}; \
568  this->deferred_factories[#_name] = [](const auto& exec, \
569  auto& params) { \
570  if (!params._name##_generator_.empty()) { \
571  params._name.clear(); \
572  for (auto& generator : params._name##_generator_) { \
573  params._name.push_back(generator.on(exec)); \
574  } \
575  } \
576  }; \
577  return *(this->self()); \
578  } \
579  template <typename FactoryType, \
580  typename = std::enable_if_t<std::is_convertible< \
581  FactoryType, \
582  ::gko::deferred_factory_parameter<_name##_type>>::value>> \
583  auto with_##_name(const std::vector<FactoryType>& factories) \
584  ->std::decay_t<decltype(*(this->self()))>& \
585  { \
586  this->_name##_generator_.clear(); \
587  for (const auto& factory : factories) { \
588  this->_name##_generator_.push_back(factory); \
589  } \
590  this->deferred_factories[#_name] = [](const auto& exec, \
591  auto& params) { \
592  if (!params._name##_generator_.empty()) { \
593  params._name.clear(); \
594  for (auto& generator : params._name##_generator_) { \
595  params._name.push_back(generator.on(exec)); \
596  } \
597  } \
598  }; \
599  return *(this->self()); \
600  } \
601  \
602 private: \
603  std::vector<::gko::deferred_factory_parameter<_name##_type>> \
604  _name##_generator_; \
605  \
606 public: \
607  static_assert(true, \
608  "This assert is used to counter the false positive extra " \
609  "semi-colon warnings")
610 
611 
612 } // namespace gko
613 
614 
615 #endif // GKO_PUBLIC_CORE_BASE_ABSTRACT_FACTORY_HPP_
gko::deferred_factory_parameter::deferred_factory_parameter
deferred_factory_parameter()=default
Creates an empty deferred factory parameter.
gko::AbstractFactory
The AbstractFactory is a generic interface template that enables easy implementation of the abstract ...
Definition: abstract_factory.hpp:45
gko::enable_parameters_type::on
std::unique_ptr< Factory > on(std::shared_ptr< const Executor > exec) const
Creates a new factory on the specified executor.
Definition: abstract_factory.hpp:225
gko::deferred_factory_parameter::on
std::shared_ptr< FactoryType > on(std::shared_ptr< const Executor > exec) const
Instantiates the deferred parameter into an actual factory.
Definition: abstract_factory.hpp:361
gko::PolymorphicObject
A PolymorphicObject is the abstract base for all "heavy" objects in Ginkgo that behave polymorphicall...
Definition: polymorphic_object.hpp:46
gko::AbstractFactory::generate
std::unique_ptr< abstract_product_type > generate(Args &&... args) const
Creates a new product from the given components.
Definition: abstract_factory.hpp:65
gko::EnableDefaultFactory
This mixin provides a default implementation of a concrete factory.
Definition: abstract_factory.hpp:122
gko::EnableDefaultFactory::create
static parameters_type create()
Creates a new ParametersType object which can be used to instantiate a new ConcreteFactory.
Definition: abstract_factory.hpp:162
gko::EnableDefaultFactory::get_parameters
const parameters_type & get_parameters() const noexcept
Returns the parameters of the factory.
Definition: abstract_factory.hpp:145
gko
The Ginkgo namespace.
Definition: abstract_factory.hpp:20
gko::deferred_factory_parameter::deferred_factory_parameter
deferred_factory_parameter(ParametersType parameters)
Creates a deferred factory parameter object from a factory_parameters-like object.
Definition: abstract_factory.hpp:351
gko::deferred_factory_parameter::deferred_factory_parameter
deferred_factory_parameter(std::unique_ptr< ConcreteFactoryType, Deleter > factory)
Creates a deferred factory parameter by taking ownership of a preexisting factory with unique ownersh...
Definition: abstract_factory.hpp:333
gko::deferred_factory_parameter::deferred_factory_parameter
deferred_factory_parameter(std::shared_ptr< ConcreteFactoryType > factory)
Creates a deferred factory parameter from a preexisting factory with shared ownership.
Definition: abstract_factory.hpp:319
gko::deferred_factory_parameter::deferred_factory_parameter
deferred_factory_parameter(std::nullptr_t)
Creates a deferred factory parameter returning a nullptr.
Definition: abstract_factory.hpp:307
gko::enable_parameters_type::with_loggers
ConcreteParametersType & with_loggers(Args &&... _value)
Provides the loggers to be added to the factory and its generated objects in a fluent interface.
Definition: abstract_factory.hpp:212
gko::enable_parameters_type
The enable_parameters_type mixin is used to create a base implementation of the factory parameters st...
Definition: abstract_factory.hpp:203
gko::deferred_factory_parameter::is_empty
bool is_empty() const
Returns true iff the parameter is empty.
Definition: abstract_factory.hpp:370
gko::deferred_factory_parameter
Represents a factory parameter of factory type that can either initialized by a pre-existing factory ...
Definition: abstract_factory.hpp:301