Ginkgo  Generated from pipelines/2837190956 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 
19 namespace gko {
20 namespace detail {
21 
32 template <typename T>
33 struct element_type {
34  using type = typename T::element_type;
35 };
36 
37 template <typename T>
38 using element_type_t = typename element_type<T>::type;
39 
40 
48 template <typename T>
49 using value_element_type_t = typename T::value_type::element_type;
50 
51 
52 } // namespace detail
53 
54 
76 template <typename AbstractProductType, typename ComponentsType>
78 public:
79  using abstract_product_type = AbstractProductType;
80  using components_type = ComponentsType;
81 
96  template <typename... Args>
97  std::unique_ptr<abstract_product_type> generate(Args&&... args) const
98  {
99  auto product =
100  this->generate_impl(components_type{std::forward<Args>(args)...});
101  for (auto logger : this->loggers_) {
102  product->add_logger(logger);
103  }
104  return product;
105  }
106 
107 protected:
113  AbstractFactory(std::shared_ptr<const Executor> exec)
114  : PolymorphicObject(std::move(exec))
115  {}
116 
124  virtual std::unique_ptr<abstract_product_type> generate_impl(
125  ComponentsType args) const = 0;
126 };
127 
128 
152 template <typename ConcreteFactory, typename ProductType,
153  typename ParametersType, typename PolymorphicBase>
154 class EnableDefaultFactory : public PolymorphicBase {
155 public:
156  using product_type = ProductType;
157  using parameters_type = ParametersType;
158  using polymorphic_base = PolymorphicBase;
159  using abstract_product_type =
160  typename PolymorphicBase::abstract_product_type;
161  using components_type = typename PolymorphicBase::components_type;
162 
163  template <typename... Args>
164  std::unique_ptr<product_type> generate(Args&&... args) const
165  {
166  auto product = std::unique_ptr<product_type>(static_cast<product_type*>(
167  this->polymorphic_base::generate(std::forward<Args>(args)...)
168  .release()));
169  return product;
170  }
171 
177  const parameters_type& get_parameters() const noexcept
178  {
179  return parameters_;
180  };
181 
194  static parameters_type create() { return {}; }
195 
196 protected:
203  explicit EnableDefaultFactory(std::shared_ptr<const Executor> exec,
204  const parameters_type& parameters = {})
205  : PolymorphicBase(std::move(exec)), parameters_{parameters}
206  {}
207 
208  std::unique_ptr<abstract_product_type> generate_impl(
209  components_type args) const override
210  {
211  return std::unique_ptr<abstract_product_type>(
212  new product_type(self(), args));
213  }
214 
215 private:
216  GKO_ENABLE_SELF(ConcreteFactory);
217 
218  ParametersType parameters_;
219 };
220 
221 
234 template <typename ConcreteParametersType, typename Factory>
236 public:
237  using factory = Factory;
238 
243  template <typename... Args>
244  ConcreteParametersType& with_loggers(Args&&... _value)
245  {
246  this->loggers = {std::forward<Args>(_value)...};
247  return *self();
248  }
249 
257  std::unique_ptr<Factory> on(std::shared_ptr<const Executor> exec) const
258  {
259  ConcreteParametersType copy = *self();
260  for (const auto& item : deferred_factories) {
261  item.second(exec, copy);
262  }
263  auto factory = std::unique_ptr<Factory>(new Factory(exec, copy));
264  for (auto& logger : loggers) {
265  factory->add_logger(logger);
266  };
267  return factory;
268  }
269 
270 protected:
271  GKO_ENABLE_SELF(ConcreteParametersType);
272 
276  std::vector<std::shared_ptr<const log::Logger>> loggers{};
277 
284  std::unordered_map<std::string,
285  std::function<void(std::shared_ptr<const Executor> exec,
286  ConcreteParametersType&)>>
287  deferred_factories;
288 };
289 
290 
304 #define GKO_CREATE_FACTORY_PARAMETERS(_parameters_name, _factory_name) \
305 public: \
306  class _factory_name; \
307  struct _parameters_name##_type \
308  : public ::gko::enable_parameters_type<_parameters_name##_type, \
309  _factory_name>
310 
311 
312 namespace detail {
313 
314 
315 // Use pointer not the type because std::is_convertible<const type, type> can be
316 // true.
317 template <typename From, typename To>
318 struct is_pointer_convertible : std::is_convertible<From*, To*> {};
319 
320 
321 } // namespace detail
322 
323 
332 template <typename FactoryType>
334 public:
336  deferred_factory_parameter() = default;
337 
340  {
341  generator_ = [](std::shared_ptr<const Executor>) { return nullptr; };
342  }
343 
348  template <typename ConcreteFactoryType,
349  std::enable_if_t<detail::is_pointer_convertible<
350  ConcreteFactoryType, FactoryType>::value>* = nullptr>
351  deferred_factory_parameter(std::shared_ptr<ConcreteFactoryType> factory)
352  {
353  generator_ = [factory =
354  std::shared_ptr<FactoryType>(std::move(factory))](
355  std::shared_ptr<const Executor>) { return factory; };
356  }
357 
362  template <typename ConcreteFactoryType, typename Deleter,
363  std::enable_if_t<detail::is_pointer_convertible<
364  ConcreteFactoryType, FactoryType>::value>* = nullptr>
366  std::unique_ptr<ConcreteFactoryType, Deleter> factory)
367  {
368  generator_ = [factory =
369  std::shared_ptr<FactoryType>(std::move(factory))](
370  std::shared_ptr<const Executor>) { return factory; };
371  }
372 
378  template <typename ParametersType,
379  typename U = decltype(std::declval<ParametersType>().on(
380  std::shared_ptr<const Executor>{})),
381  std::enable_if_t<detail::is_pointer_convertible<
382  typename U::element_type, FactoryType>::value>* = nullptr>
383  deferred_factory_parameter(ParametersType parameters)
384  {
385  generator_ = [parameters](std::shared_ptr<const Executor> exec)
386  -> std::shared_ptr<FactoryType> { return parameters.on(exec); };
387  }
388 
393  std::shared_ptr<FactoryType> on(std::shared_ptr<const Executor> exec) const
394  {
395  if (this->is_empty()) {
396  GKO_NOT_SUPPORTED(*this);
397  }
398  return generator_(exec);
399  }
400 
402  bool is_empty() const { return !bool(generator_); }
403 
404 private:
405  std::function<std::shared_ptr<FactoryType>(std::shared_ptr<const Executor>)>
406  generator_;
407 };
408 
409 
418 #define GKO_ENABLE_BUILD_METHOD(_factory_name) \
419  static auto build()->decltype(_factory_name::create()) \
420  { \
421  return _factory_name::create(); \
422  } \
423  static_assert(true, \
424  "This assert is used to counter the false positive extra " \
425  "semi-colon warnings")
426 
427 
428 #if !(defined(__CUDACC__) || defined(__HIPCC__))
429 
441 #define GKO_FACTORY_PARAMETER(_name, ...) \
442  _name{__VA_ARGS__}; \
443  \
444  template <typename... Args> \
445  auto with_##_name(Args&&... _value) \
446  ->std::decay_t<decltype(*(this->self()))>& \
447  { \
448  using type = decltype(this->_name); \
449  this->_name = type{std::forward<Args>(_value)...}; \
450  return *(this->self()); \
451  } \
452  static_assert(true, \
453  "This assert is used to counter the false positive extra " \
454  "semi-colon warnings")
455 
469 #define GKO_FACTORY_PARAMETER_SCALAR(_name, _default) \
470  GKO_FACTORY_PARAMETER(_name, _default)
471 
485 #define GKO_FACTORY_PARAMETER_VECTOR(_name, ...) \
486  GKO_FACTORY_PARAMETER(_name, __VA_ARGS__)
487 #else // defined(__CUDACC__) || defined(__HIPCC__)
488 // A workaround for the NVCC compiler - parameter pack expansion does not work
489 // properly, because while the assignment to a scalar value is translated by
490 // cudafe into a C-style cast, the parameter pack expansion is not removed and
491 // `Args&&... args` is still kept as a parameter pack.
492 #define GKO_FACTORY_PARAMETER(_name, ...) \
493  _name{__VA_ARGS__}; \
494  \
495  template <typename... Args> \
496  auto with_##_name(Args&&... _value) \
497  ->std::decay_t<decltype(*(this->self()))>& \
498  { \
499  GKO_NOT_IMPLEMENTED; \
500  return *(this->self()); \
501  } \
502  static_assert(true, \
503  "This assert is used to counter the false positive extra " \
504  "semi-colon warnings")
505 
506 #define GKO_FACTORY_PARAMETER_SCALAR(_name, _default) \
507  _name{_default}; \
508  \
509  template <typename Arg> \
510  auto with_##_name(Arg&& _value)->std::decay_t<decltype(*(this->self()))>& \
511  { \
512  using type = decltype(this->_name); \
513  this->_name = type{std::forward<Arg>(_value)}; \
514  return *(this->self()); \
515  } \
516  static_assert(true, \
517  "This assert is used to counter the false positive extra " \
518  "semi-colon warnings")
519 
520 #define GKO_FACTORY_PARAMETER_VECTOR(_name, ...) \
521  _name{__VA_ARGS__}; \
522  \
523  template <typename... Args> \
524  auto with_##_name(Args&&... _value) \
525  ->std::decay_t<decltype(*(this->self()))>& \
526  { \
527  using type = decltype(this->_name); \
528  this->_name = type{std::forward<Args>(_value)...}; \
529  return *(this->self()); \
530  } \
531  static_assert(true, \
532  "This assert is used to counter the false positive extra " \
533  "semi-colon warnings")
534 #endif // defined(__CUDACC__) || defined(__HIPCC__)
535 
545 #define GKO_DEFERRED_FACTORY_PARAMETER(_name) \
546  _name{}; \
547  \
548 private: \
549  using _name##_type = ::gko::detail::element_type_t<decltype(_name)>; \
550  \
551 public: \
552  auto with_##_name(::gko::deferred_factory_parameter<_name##_type> factory) \
553  ->std::decay_t<decltype(*(this->self()))>& \
554  { \
555  this->_name##_generator_ = std::move(factory); \
556  this->deferred_factories[#_name] = [](const auto& exec, \
557  auto& params) { \
558  if (!params._name##_generator_.is_empty()) { \
559  params._name = params._name##_generator_.on(exec); \
560  } \
561  }; \
562  return *(this->self()); \
563  } \
564  \
565 private: \
566  ::gko::deferred_factory_parameter<_name##_type> _name##_generator_; \
567  \
568 public: \
569  static_assert(true, \
570  "This assert is used to counter the false positive extra " \
571  "semi-colon warnings")
572 
583 #define GKO_DEFERRED_FACTORY_VECTOR_PARAMETER(_name) \
584  _name{}; \
585  \
586 private: \
587  using _name##_type = ::gko::detail::value_element_type_t<decltype(_name)>; \
588  \
589 public: \
590  template <typename... Args, \
591  typename = std::enable_if_t<::std::conjunction< \
592  std::is_convertible<Args, ::gko::deferred_factory_parameter< \
593  _name##_type>>...>::value>> \
594  auto with_##_name(Args&&... factories) \
595  ->std::decay_t<decltype(*(this->self()))>& \
596  { \
597  this->_name##_generator_ = { \
598  ::gko::deferred_factory_parameter<_name##_type>{ \
599  std::forward<Args>(factories)}...}; \
600  this->deferred_factories[#_name] = [](const auto& exec, \
601  auto& params) { \
602  if (!params._name##_generator_.empty()) { \
603  params._name.clear(); \
604  for (auto& generator : params._name##_generator_) { \
605  params._name.push_back(generator.on(exec)); \
606  } \
607  } \
608  }; \
609  return *(this->self()); \
610  } \
611  template <typename FactoryType, \
612  typename = std::enable_if_t<std::is_convertible< \
613  FactoryType, \
614  ::gko::deferred_factory_parameter<_name##_type>>::value>> \
615  auto with_##_name(const std::vector<FactoryType>& factories) \
616  ->std::decay_t<decltype(*(this->self()))>& \
617  { \
618  this->_name##_generator_.clear(); \
619  for (const auto& factory : factories) { \
620  this->_name##_generator_.push_back(factory); \
621  } \
622  this->deferred_factories[#_name] = [](const auto& exec, \
623  auto& params) { \
624  if (!params._name##_generator_.empty()) { \
625  params._name.clear(); \
626  for (auto& generator : params._name##_generator_) { \
627  params._name.push_back(generator.on(exec)); \
628  } \
629  } \
630  }; \
631  return *(this->self()); \
632  } \
633  \
634 private: \
635  std::vector<::gko::deferred_factory_parameter<_name##_type>> \
636  _name##_generator_; \
637  \
638 public: \
639  static_assert(true, \
640  "This assert is used to counter the false positive extra " \
641  "semi-colon warnings")
642 
643 
644 } // namespace gko
645 
646 
647 #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:77
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:257
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:393
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:97
gko::EnableDefaultFactory
This mixin provides a default implementation of a concrete factory.
Definition: abstract_factory.hpp:154
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:194
gko::EnableDefaultFactory::get_parameters
const parameters_type & get_parameters() const noexcept
Returns the parameters of the factory.
Definition: abstract_factory.hpp:177
gko
The Ginkgo namespace.
Definition: abstract_factory.hpp:19
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:383
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:365
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:351
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:339
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:244
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:235
gko::deferred_factory_parameter::is_empty
bool is_empty() const
Returns true iff the parameter is empty.
Definition: abstract_factory.hpp:402
gko::deferred_factory_parameter
Represents a factory parameter of factory type that can either initialized by a pre-existing factory ...
Definition: abstract_factory.hpp:333