Ginkgo Generated from branch based on master. Ginkgo version 1.8.0
A numerical linear algebra library targeting many-core architectures
Loading...
Searching...
No Matches
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 <unordered_map>
10
11
12#include <ginkgo/core/base/polymorphic_object.hpp>
13
14
20namespace gko {
21
22
44template <typename AbstractProductType, typename ComponentsType>
47 AbstractFactory<AbstractProductType, ComponentsType>> {
48public:
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
77protected:
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
122template <typename ConcreteFactory, typename ProductType,
123 typename ParametersType, typename PolymorphicBase>
125 : public EnablePolymorphicObject<ConcreteFactory, PolymorphicBase>,
126 public EnablePolymorphicAssignment<ConcreteFactory> {
127public:
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
170protected:
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
191private:
192 GKO_ENABLE_SELF(ConcreteFactory);
193
194 ParametersType parameters_;
195};
196
197
210template <typename ConcreteParametersType, typename Factory>
212public:
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
246protected:
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) \
281public: \
282 class _factory_name; \
283 struct _parameters_name##_type \
284 : public ::gko::enable_parameters_type<_parameters_name##_type, \
285 _factory_name>
286
287
288namespace detail {
289
290
291// Use pointer not the type because std::is_convertible<const type, type> can be
292// true.
293template <typename From, typename To>
294struct is_pointer_convertible : std::is_convertible<From*, To*> {};
295
296
297} // namespace detail
298
299
308template <typename FactoryType>
310public:
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
380private:
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__))
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 \
524private: \
525 using _name##_type = typename decltype(_name)::element_type; \
526 \
527public: \
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 \
541private: \
542 ::gko::deferred_factory_parameter<_name##_type> _name##_generator_; \
543 \
544public: \
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 \
562private: \
563 using _name##_type = typename decltype(_name)::value_type::element_type; \
564 \
565public: \
566 template <typename... Args, \
567 typename = std::enable_if_t<::gko::xstd::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 \
610private: \
611 std::vector<::gko::deferred_factory_parameter<_name##_type>> \
612 _name##_generator_; \
613 \
614public: \
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_
The AbstractFactory is a generic interface template that enables easy implementation of the abstract ...
Definition abstract_factory.hpp:47
std::unique_ptr< abstract_product_type > generate(Args &&... args) const
Creates a new product from the given components.
Definition abstract_factory.hpp:67
This mixin inherits from (a subclass of) PolymorphicObject and provides a base implementation of a ne...
Definition polymorphic_object.hpp:346
This mixin provides a default implementation of a concrete factory.
Definition abstract_factory.hpp:126
static parameters_type create()
Creates a new ParametersType object which can be used to instantiate a new ConcreteFactory.
Definition abstract_factory.hpp:168
const parameters_type & get_parameters() const noexcept
Returns the parameters of the factory.
Definition abstract_factory.hpp:151
This mixin is used to enable a default PolymorphicObject::copy_from() implementation for objects that...
Definition polymorphic_object.hpp:724
This mixin inherits from (a subclass of) PolymorphicObject and provides a base implementation of a ne...
Definition polymorphic_object.hpp:663
Represents a factory parameter of factory type that can either initialized by a pre-existing factory ...
Definition abstract_factory.hpp:309
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
bool is_empty() const
Returns true iff the parameter is empty.
Definition abstract_factory.hpp:378
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
deferred_factory_parameter()=default
Creates an empty deferred factory parameter.
deferred_factory_parameter(std::nullptr_t)
Creates a deferred factory parameter returning a nullptr.
Definition abstract_factory.hpp:315
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
deferred_factory_parameter(ParametersType parameters)
Creates a deferred factory parameter object from a factory_parameters-like object.
Definition abstract_factory.hpp:359
The enable_parameters_type mixin is used to create a base implementation of the factory parameters st...
Definition abstract_factory.hpp:211
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
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
The Ginkgo namespace.
Definition abstract_factory.hpp:20