Ginkgo  Generated from pipelines/1478841010 branch based on develop. Ginkgo version 1.9.0
A numerical linear algebra library targeting many-core architectures
abstract_factory.hpp
1 // SPDX-FileCopyrightText: 2017 - 2024 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>
47  AbstractFactory<AbstractProductType, ComponentsType>> {
48 public:
49  using abstract_product_type = AbstractProductType;
50  using components_type = ComponentsType;
51 
66  template <typename... Args>
67  std::unique_ptr<abstract_product_type> generate(Args&&... args) const
68  {
69  auto product =
70  this->generate_impl(components_type{std::forward<Args>(args)...});
71  for (auto logger : this->loggers_) {
72  product->add_logger(logger);
73  }
74  return product;
75  }
76 
77 protected:
83  AbstractFactory(std::shared_ptr<const Executor> exec)
85  {}
86 
94  virtual std::unique_ptr<abstract_product_type> generate_impl(
95  ComponentsType args) const = 0;
96 };
97 
98 
122 template <typename ConcreteFactory, typename ProductType,
123  typename ParametersType, typename PolymorphicBase>
125  : public EnablePolymorphicObject<ConcreteFactory, PolymorphicBase>,
126  public EnablePolymorphicAssignment<ConcreteFactory> {
127 public:
128  friend class EnablePolymorphicObject<ConcreteFactory, PolymorphicBase>;
129 
130  using product_type = ProductType;
131  using parameters_type = ParametersType;
132  using polymorphic_base = PolymorphicBase;
133  using abstract_product_type =
134  typename PolymorphicBase::abstract_product_type;
135  using components_type = typename PolymorphicBase::components_type;
136 
137  template <typename... Args>
138  std::unique_ptr<product_type> generate(Args&&... args) const
139  {
140  auto product = std::unique_ptr<product_type>(static_cast<product_type*>(
141  this->polymorphic_base::generate(std::forward<Args>(args)...)
142  .release()));
143  return product;
144  }
145 
151  const parameters_type& get_parameters() const noexcept
152  {
153  return parameters_;
154  };
155 
168  static parameters_type create() { return {}; }
169 
170 protected:
177  explicit EnableDefaultFactory(std::shared_ptr<const Executor> exec,
178  const parameters_type& parameters = {})
179  : EnablePolymorphicObject<ConcreteFactory, PolymorphicBase>(
180  std::move(exec)),
181  parameters_{parameters}
182  {}
183 
184  std::unique_ptr<abstract_product_type> generate_impl(
185  components_type args) const override
186  {
187  return std::unique_ptr<abstract_product_type>(
188  new product_type(self(), args));
189  }
190 
191 private:
192  GKO_ENABLE_SELF(ConcreteFactory);
193 
194  ParametersType parameters_;
195 };
196 
197 
210 template <typename ConcreteParametersType, typename Factory>
212 public:
213  using factory = Factory;
214 
219  template <typename... Args>
220  ConcreteParametersType& with_loggers(Args&&... _value)
221  {
222  this->loggers = {std::forward<Args>(_value)...};
223  return *self();
224  }
225 
233  std::unique_ptr<Factory> on(std::shared_ptr<const Executor> exec) const
234  {
235  ConcreteParametersType copy = *self();
236  for (const auto& item : deferred_factories) {
237  item.second(exec, copy);
238  }
239  auto factory = std::unique_ptr<Factory>(new Factory(exec, copy));
240  for (auto& logger : loggers) {
241  factory->add_logger(logger);
242  };
243  return factory;
244  }
245 
246 protected:
247  GKO_ENABLE_SELF(ConcreteParametersType);
248 
252  std::vector<std::shared_ptr<const log::Logger>> loggers{};
253 
260  std::unordered_map<std::string,
261  std::function<void(std::shared_ptr<const Executor> exec,
262  ConcreteParametersType&)>>
263  deferred_factories;
264 };
265 
266 
280 #define GKO_CREATE_FACTORY_PARAMETERS(_parameters_name, _factory_name) \
281 public: \
282  class _factory_name; \
283  struct _parameters_name##_type \
284  : public ::gko::enable_parameters_type<_parameters_name##_type, \
285  _factory_name>
286 
287 
288 namespace detail {
289 
290 
291 // Use pointer not the type because std::is_convertible<const type, type> can be
292 // true.
293 template <typename From, typename To>
294 struct is_pointer_convertible : std::is_convertible<From*, To*> {};
295 
296 
297 } // namespace detail
298 
299 
308 template <typename FactoryType>
310 public:
312  deferred_factory_parameter() = default;
313 
316  {
317  generator_ = [](std::shared_ptr<const Executor>) { return nullptr; };
318  }
319 
324  template <typename ConcreteFactoryType,
325  std::enable_if_t<detail::is_pointer_convertible<
326  ConcreteFactoryType, FactoryType>::value>* = nullptr>
327  deferred_factory_parameter(std::shared_ptr<ConcreteFactoryType> factory)
328  {
329  generator_ = [factory =
330  std::shared_ptr<FactoryType>(std::move(factory))](
331  std::shared_ptr<const Executor>) { return factory; };
332  }
333 
338  template <typename ConcreteFactoryType, typename Deleter,
339  std::enable_if_t<detail::is_pointer_convertible<
340  ConcreteFactoryType, FactoryType>::value>* = nullptr>
342  std::unique_ptr<ConcreteFactoryType, Deleter> factory)
343  {
344  generator_ = [factory =
345  std::shared_ptr<FactoryType>(std::move(factory))](
346  std::shared_ptr<const Executor>) { return factory; };
347  }
348 
354  template <typename ParametersType,
355  typename U = decltype(std::declval<ParametersType>().on(
356  std::shared_ptr<const Executor>{})),
357  std::enable_if_t<detail::is_pointer_convertible<
358  typename U::element_type, FactoryType>::value>* = nullptr>
359  deferred_factory_parameter(ParametersType parameters)
360  {
361  generator_ = [parameters](std::shared_ptr<const Executor> exec)
362  -> std::shared_ptr<FactoryType> { return parameters.on(exec); };
363  }
364 
369  std::shared_ptr<FactoryType> on(std::shared_ptr<const Executor> exec) const
370  {
371  if (this->is_empty()) {
372  GKO_NOT_SUPPORTED(*this);
373  }
374  return generator_(exec);
375  }
376 
378  bool is_empty() const { return !bool(generator_); }
379 
380 private:
381  std::function<std::shared_ptr<FactoryType>(std::shared_ptr<const Executor>)>
382  generator_;
383 };
384 
385 
394 #define GKO_ENABLE_BUILD_METHOD(_factory_name) \
395  static auto build()->decltype(_factory_name::create()) \
396  { \
397  return _factory_name::create(); \
398  } \
399  static_assert(true, \
400  "This assert is used to counter the false positive extra " \
401  "semi-colon warnings")
402 
403 
404 #if !(defined(__CUDACC__) || defined(__HIPCC__))
405 
417 #define GKO_FACTORY_PARAMETER(_name, ...) \
418  _name{__VA_ARGS__}; \
419  \
420  template <typename... Args> \
421  auto with_##_name(Args&&... _value) \
422  ->std::decay_t<decltype(*(this->self()))>& \
423  { \
424  using type = decltype(this->_name); \
425  this->_name = type{std::forward<Args>(_value)...}; \
426  return *(this->self()); \
427  } \
428  static_assert(true, \
429  "This assert is used to counter the false positive extra " \
430  "semi-colon warnings")
431 
445 #define GKO_FACTORY_PARAMETER_SCALAR(_name, _default) \
446  GKO_FACTORY_PARAMETER(_name, _default)
447 
461 #define GKO_FACTORY_PARAMETER_VECTOR(_name, ...) \
462  GKO_FACTORY_PARAMETER(_name, __VA_ARGS__)
463 #else // defined(__CUDACC__) || defined(__HIPCC__)
464 // A workaround for the NVCC compiler - parameter pack expansion does not work
465 // properly, because while the assignment to a scalar value is translated by
466 // cudafe into a C-style cast, the parameter pack expansion is not removed and
467 // `Args&&... args` is still kept as a parameter pack.
468 #define GKO_FACTORY_PARAMETER(_name, ...) \
469  _name{__VA_ARGS__}; \
470  \
471  template <typename... Args> \
472  auto with_##_name(Args&&... _value) \
473  ->std::decay_t<decltype(*(this->self()))>& \
474  { \
475  GKO_NOT_IMPLEMENTED; \
476  return *(this->self()); \
477  } \
478  static_assert(true, \
479  "This assert is used to counter the false positive extra " \
480  "semi-colon warnings")
481 
482 #define GKO_FACTORY_PARAMETER_SCALAR(_name, _default) \
483  _name{_default}; \
484  \
485  template <typename Arg> \
486  auto with_##_name(Arg&& _value)->std::decay_t<decltype(*(this->self()))>& \
487  { \
488  using type = decltype(this->_name); \
489  this->_name = type{std::forward<Arg>(_value)}; \
490  return *(this->self()); \
491  } \
492  static_assert(true, \
493  "This assert is used to counter the false positive extra " \
494  "semi-colon warnings")
495 
496 #define GKO_FACTORY_PARAMETER_VECTOR(_name, ...) \
497  _name{__VA_ARGS__}; \
498  \
499  template <typename... Args> \
500  auto with_##_name(Args&&... _value) \
501  ->std::decay_t<decltype(*(this->self()))>& \
502  { \
503  using type = decltype(this->_name); \
504  this->_name = type{std::forward<Args>(_value)...}; \
505  return *(this->self()); \
506  } \
507  static_assert(true, \
508  "This assert is used to counter the false positive extra " \
509  "semi-colon warnings")
510 #endif // defined(__CUDACC__) || defined(__HIPCC__)
511 
521 #define GKO_DEFERRED_FACTORY_PARAMETER(_name) \
522  _name{}; \
523  \
524 private: \
525  using _name##_type = typename decltype(_name)::element_type; \
526  \
527 public: \
528  auto with_##_name(::gko::deferred_factory_parameter<_name##_type> factory) \
529  ->std::decay_t<decltype(*(this->self()))>& \
530  { \
531  this->_name##_generator_ = std::move(factory); \
532  this->deferred_factories[#_name] = [](const auto& exec, \
533  auto& params) { \
534  if (!params._name##_generator_.is_empty()) { \
535  params._name = params._name##_generator_.on(exec); \
536  } \
537  }; \
538  return *(this->self()); \
539  } \
540  \
541 private: \
542  ::gko::deferred_factory_parameter<_name##_type> _name##_generator_; \
543  \
544 public: \
545  static_assert(true, \
546  "This assert is used to counter the false positive extra " \
547  "semi-colon warnings")
548 
559 #define GKO_DEFERRED_FACTORY_VECTOR_PARAMETER(_name) \
560  _name{}; \
561  \
562 private: \
563  using _name##_type = typename decltype(_name)::value_type::element_type; \
564  \
565 public: \
566  template <typename... Args, \
567  typename = std::enable_if_t<::std::conjunction< \
568  std::is_convertible<Args, ::gko::deferred_factory_parameter< \
569  _name##_type>>...>::value>> \
570  auto with_##_name(Args&&... factories) \
571  ->std::decay_t<decltype(*(this->self()))>& \
572  { \
573  this->_name##_generator_ = { \
574  ::gko::deferred_factory_parameter<_name##_type>{ \
575  std::forward<Args>(factories)}...}; \
576  this->deferred_factories[#_name] = [](const auto& exec, \
577  auto& params) { \
578  if (!params._name##_generator_.empty()) { \
579  params._name.clear(); \
580  for (auto& generator : params._name##_generator_) { \
581  params._name.push_back(generator.on(exec)); \
582  } \
583  } \
584  }; \
585  return *(this->self()); \
586  } \
587  template <typename FactoryType, \
588  typename = std::enable_if_t<std::is_convertible< \
589  FactoryType, \
590  ::gko::deferred_factory_parameter<_name##_type>>::value>> \
591  auto with_##_name(const std::vector<FactoryType>& factories) \
592  ->std::decay_t<decltype(*(this->self()))>& \
593  { \
594  this->_name##_generator_.clear(); \
595  for (const auto& factory : factories) { \
596  this->_name##_generator_.push_back(factory); \
597  } \
598  this->deferred_factories[#_name] = [](const auto& exec, \
599  auto& params) { \
600  if (!params._name##_generator_.empty()) { \
601  params._name.clear(); \
602  for (auto& generator : params._name##_generator_) { \
603  params._name.push_back(generator.on(exec)); \
604  } \
605  } \
606  }; \
607  return *(this->self()); \
608  } \
609  \
610 private: \
611  std::vector<::gko::deferred_factory_parameter<_name##_type>> \
612  _name##_generator_; \
613  \
614 public: \
615  static_assert(true, \
616  "This assert is used to counter the false positive extra " \
617  "semi-colon warnings")
618 
619 
620 } // namespace gko
621 
622 
623 #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:233
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:369
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:67
gko::EnableAbstractPolymorphicObject
This mixin inherits from (a subclass of) PolymorphicObject and provides a base implementation of a ne...
Definition: polymorphic_object.hpp:345
gko::EnableDefaultFactory
This mixin provides a default implementation of a concrete factory.
Definition: abstract_factory.hpp:124
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:168
gko::EnableDefaultFactory::get_parameters
const parameters_type & get_parameters() const noexcept
Returns the parameters of the factory.
Definition: abstract_factory.hpp:151
gko::EnablePolymorphicAssignment
This mixin is used to enable a default PolymorphicObject::copy_from() implementation for objects that...
Definition: polymorphic_object.hpp:723
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:359
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:341
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:327
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:315
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:220
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:211
gko::deferred_factory_parameter::is_empty
bool is_empty() const
Returns true iff the parameter is empty.
Definition: abstract_factory.hpp:378
gko::deferred_factory_parameter
Represents a factory parameter of factory type that can either initialized by a pre-existing factory ...
Definition: abstract_factory.hpp:309
gko::EnablePolymorphicObject
This mixin inherits from (a subclass of) PolymorphicObject and provides a base implementation of a ne...
Definition: polymorphic_object.hpp:661