Ginkgo Generated from branch based on master. Ginkgo version 1.7.0
A numerical linear algebra library targeting many-core architectures
Loading...
Searching...
No Matches
abstract_factory.hpp
1/*******************************<GINKGO LICENSE>******************************
2Copyright (c) 2017-2023, the Ginkgo authors
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, are permitted provided that the following conditions
7are met:
8
91. Redistributions of source code must retain the above copyright
10notice, this list of conditions and the following disclaimer.
11
122. Redistributions in binary form must reproduce the above copyright
13notice, this list of conditions and the following disclaimer in the
14documentation and/or other materials provided with the distribution.
15
163. Neither the name of the copyright holder nor the names of its
17contributors may be used to endorse or promote products derived from
18this software without specific prior written permission.
19
20THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
21IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31******************************<GINKGO LICENSE>*******************************/
32
33#ifndef GKO_PUBLIC_CORE_BASE_ABSTRACT_FACTORY_HPP_
34#define GKO_PUBLIC_CORE_BASE_ABSTRACT_FACTORY_HPP_
35
36
37#include <unordered_map>
38
39
40#include <ginkgo/core/base/polymorphic_object.hpp>
41
42
48namespace gko {
49
50
72template <typename AbstractProductType, typename ComponentsType>
75 AbstractFactory<AbstractProductType, ComponentsType>> {
76public:
77 using abstract_product_type = AbstractProductType;
78 using components_type = ComponentsType;
79
94 template <typename... Args>
95 std::unique_ptr<abstract_product_type> generate(Args&&... args) const
96 {
97 auto product =
98 this->generate_impl(components_type{std::forward<Args>(args)...});
99 for (auto logger : this->loggers_) {
100 product->add_logger(logger);
101 }
102 return product;
103 }
104
105protected:
111 AbstractFactory(std::shared_ptr<const Executor> exec)
113 {}
114
122 virtual std::unique_ptr<abstract_product_type> generate_impl(
123 ComponentsType args) const = 0;
124};
125
126
150template <typename ConcreteFactory, typename ProductType,
151 typename ParametersType, typename PolymorphicBase>
153 : public EnablePolymorphicObject<ConcreteFactory, PolymorphicBase>,
154 public EnablePolymorphicAssignment<ConcreteFactory> {
155public:
156 friend class EnablePolymorphicObject<ConcreteFactory, PolymorphicBase>;
157
158 using product_type = ProductType;
159 using parameters_type = ParametersType;
160 using polymorphic_base = PolymorphicBase;
161 using abstract_product_type =
162 typename PolymorphicBase::abstract_product_type;
163 using components_type = typename PolymorphicBase::components_type;
164
165 template <typename... Args>
166 std::unique_ptr<product_type> generate(Args&&... args) const
167 {
168 auto product = std::unique_ptr<product_type>(static_cast<product_type*>(
169 this->polymorphic_base::generate(std::forward<Args>(args)...)
170 .release()));
171 return product;
172 }
173
179 const parameters_type& get_parameters() const noexcept
180 {
181 return parameters_;
182 };
183
196 static parameters_type create() { return {}; }
197
198protected:
205 explicit EnableDefaultFactory(std::shared_ptr<const Executor> exec,
206 const parameters_type& parameters = {})
207 : EnablePolymorphicObject<ConcreteFactory, PolymorphicBase>(
208 std::move(exec)),
209 parameters_{parameters}
210 {}
211
212 std::unique_ptr<abstract_product_type> generate_impl(
213 components_type args) const override
214 {
215 return std::unique_ptr<abstract_product_type>(
216 new product_type(self(), args));
217 }
218
219private:
220 GKO_ENABLE_SELF(ConcreteFactory);
221
222 ParametersType parameters_;
223};
224
225
238template <typename ConcreteParametersType, typename Factory>
240public:
241 using factory = Factory;
242
247 template <typename... Args>
249 {
250 this->loggers = {std::forward<Args>(_value)...};
251 return *self();
252 }
253
261 std::unique_ptr<Factory> on(std::shared_ptr<const Executor> exec) const
262 {
263 ConcreteParametersType copy = *self();
264 for (const auto& item : deferred_factories) {
265 item.second(exec, copy);
266 }
267 auto factory = std::unique_ptr<Factory>(new Factory(exec, copy));
268 for (auto& logger : loggers) {
269 factory->add_logger(logger);
270 };
271 return factory;
272 }
273
274protected:
275 GKO_ENABLE_SELF(ConcreteParametersType);
276
280 std::vector<std::shared_ptr<const log::Logger>> loggers{};
281
288 std::unordered_map<std::string,
289 std::function<void(std::shared_ptr<const Executor> exec,
291 deferred_factories;
292};
293
294
308#define GKO_CREATE_FACTORY_PARAMETERS(_parameters_name, _factory_name) \
309public: \
310 class _factory_name; \
311 struct _parameters_name##_type \
312 : public ::gko::enable_parameters_type<_parameters_name##_type, \
313 _factory_name>
314
315
316namespace detail {
317
318
319// Use pointer not the type because std::is_convertible<const type, type> can be
320// true.
321template <typename From, typename To>
322struct is_pointer_convertible : std::is_convertible<From*, To*> {};
323
324
325} // namespace detail
326
327
336template <typename FactoryType>
338public:
341
344 {
345 generator_ = [](std::shared_ptr<const Executor>) { return nullptr; };
346 }
347
352 template <typename ConcreteFactoryType,
353 std::enable_if_t<detail::is_pointer_convertible<
354 ConcreteFactoryType, FactoryType>::value>* = nullptr>
355 deferred_factory_parameter(std::shared_ptr<ConcreteFactoryType> factory)
356 {
357 generator_ = [factory =
358 std::shared_ptr<FactoryType>(std::move(factory))](
359 std::shared_ptr<const Executor>) { return factory; };
360 }
361
366 template <typename ConcreteFactoryType, typename Deleter,
367 std::enable_if_t<detail::is_pointer_convertible<
368 ConcreteFactoryType, FactoryType>::value>* = nullptr>
370 std::unique_ptr<ConcreteFactoryType, Deleter> factory)
371 {
372 generator_ = [factory =
373 std::shared_ptr<FactoryType>(std::move(factory))](
374 std::shared_ptr<const Executor>) { return factory; };
375 }
376
382 template <typename ParametersType,
383 typename U = decltype(std::declval<ParametersType>().on(
384 std::shared_ptr<const Executor>{})),
385 std::enable_if_t<detail::is_pointer_convertible<
386 typename U::element_type, FactoryType>::value>* = nullptr>
388 {
389 generator_ = [parameters](std::shared_ptr<const Executor> exec)
390 -> std::shared_ptr<FactoryType> { return parameters.on(exec); };
391 }
392
397 std::shared_ptr<FactoryType> on(std::shared_ptr<const Executor> exec) const
398 {
399 if (this->is_empty()) {
400 GKO_NOT_SUPPORTED(*this);
401 }
402 return generator_(exec);
403 }
404
406 bool is_empty() const { return !bool(generator_); }
407
408private:
409 std::function<std::shared_ptr<FactoryType>(std::shared_ptr<const Executor>)>
410 generator_;
411};
412
413
422#define GKO_ENABLE_BUILD_METHOD(_factory_name) \
423 static auto build()->decltype(_factory_name::create()) \
424 { \
425 return _factory_name::create(); \
426 } \
427 static_assert(true, \
428 "This assert is used to counter the false positive extra " \
429 "semi-colon warnings")
430
431
432#if !(defined(__CUDACC__) || defined(__HIPCC__))
445#define GKO_FACTORY_PARAMETER(_name, ...) \
446 _name{__VA_ARGS__}; \
447 \
448 template <typename... Args> \
449 auto with_##_name(Args&&... _value) \
450 ->std::decay_t<decltype(*(this->self()))>& \
451 { \
452 using type = decltype(this->_name); \
453 this->_name = type{std::forward<Args>(_value)...}; \
454 return *(this->self()); \
455 } \
456 static_assert(true, \
457 "This assert is used to counter the false positive extra " \
458 "semi-colon warnings")
459
473#define GKO_FACTORY_PARAMETER_SCALAR(_name, _default) \
474 GKO_FACTORY_PARAMETER(_name, _default)
475
489#define GKO_FACTORY_PARAMETER_VECTOR(_name, ...) \
490 GKO_FACTORY_PARAMETER(_name, __VA_ARGS__)
491#else // defined(__CUDACC__) || defined(__HIPCC__)
492// A workaround for the NVCC compiler - parameter pack expansion does not work
493// properly, because while the assignment to a scalar value is translated by
494// cudafe into a C-style cast, the parameter pack expansion is not removed and
495// `Args&&... args` is still kept as a parameter pack.
496#define GKO_FACTORY_PARAMETER(_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 GKO_NOT_IMPLEMENTED; \
504 return *(this->self()); \
505 } \
506 static_assert(true, \
507 "This assert is used to counter the false positive extra " \
508 "semi-colon warnings")
509
510#define GKO_FACTORY_PARAMETER_SCALAR(_name, _default) \
511 _name{_default}; \
512 \
513 template <typename Arg> \
514 auto with_##_name(Arg&& _value)->std::decay_t<decltype(*(this->self()))>& \
515 { \
516 using type = decltype(this->_name); \
517 this->_name = type{std::forward<Arg>(_value)}; \
518 return *(this->self()); \
519 } \
520 static_assert(true, \
521 "This assert is used to counter the false positive extra " \
522 "semi-colon warnings")
523
524#define GKO_FACTORY_PARAMETER_VECTOR(_name, ...) \
525 _name{__VA_ARGS__}; \
526 \
527 template <typename... Args> \
528 auto with_##_name(Args&&... _value) \
529 ->std::decay_t<decltype(*(this->self()))>& \
530 { \
531 using type = decltype(this->_name); \
532 this->_name = type{std::forward<Args>(_value)...}; \
533 return *(this->self()); \
534 } \
535 static_assert(true, \
536 "This assert is used to counter the false positive extra " \
537 "semi-colon warnings")
538#endif // defined(__CUDACC__) || defined(__HIPCC__)
539
549#define GKO_DEFERRED_FACTORY_PARAMETER(_name) \
550 _name{}; \
551 \
552private: \
553 using _name##_type = typename decltype(_name)::element_type; \
554 \
555public: \
556 auto with_##_name(::gko::deferred_factory_parameter<_name##_type> factory) \
557 ->std::decay_t<decltype(*(this->self()))>& \
558 { \
559 this->_name##_generator_ = std::move(factory); \
560 this->deferred_factories[#_name] = [](const auto& exec, \
561 auto& params) { \
562 if (!params._name##_generator_.is_empty()) { \
563 params._name = params._name##_generator_.on(exec); \
564 } \
565 }; \
566 return *(this->self()); \
567 } \
568 \
569private: \
570 ::gko::deferred_factory_parameter<_name##_type> _name##_generator_; \
571 \
572public: \
573 static_assert(true, \
574 "This assert is used to counter the false positive extra " \
575 "semi-colon warnings")
576
587#define GKO_DEFERRED_FACTORY_VECTOR_PARAMETER(_name) \
588 _name{}; \
589 \
590private: \
591 using _name##_type = typename decltype(_name)::value_type::element_type; \
592 \
593public: \
594 template <typename... Args, \
595 typename = std::enable_if_t<::gko::xstd::conjunction< \
596 std::is_convertible<Args, ::gko::deferred_factory_parameter< \
597 _name##_type>>...>::value>> \
598 auto with_##_name(Args&&... factories) \
599 ->std::decay_t<decltype(*(this->self()))>& \
600 { \
601 this->_name##_generator_ = { \
602 ::gko::deferred_factory_parameter<_name##_type>{ \
603 std::forward<Args>(factories)}...}; \
604 this->deferred_factories[#_name] = [](const auto& exec, \
605 auto& params) { \
606 if (!params._name##_generator_.empty()) { \
607 params._name.clear(); \
608 for (auto& generator : params._name##_generator_) { \
609 params._name.push_back(generator.on(exec)); \
610 } \
611 } \
612 }; \
613 return *(this->self()); \
614 } \
615 template <typename FactoryType, \
616 typename = std::enable_if_t<std::is_convertible< \
617 FactoryType, \
618 ::gko::deferred_factory_parameter<_name##_type>>::value>> \
619 auto with_##_name(const std::vector<FactoryType>& factories) \
620 ->std::decay_t<decltype(*(this->self()))>& \
621 { \
622 this->_name##_generator_.clear(); \
623 for (const auto& factory : factories) { \
624 this->_name##_generator_.push_back(factory); \
625 } \
626 this->deferred_factories[#_name] = [](const auto& exec, \
627 auto& params) { \
628 if (!params._name##_generator_.empty()) { \
629 params._name.clear(); \
630 for (auto& generator : params._name##_generator_) { \
631 params._name.push_back(generator.on(exec)); \
632 } \
633 } \
634 }; \
635 return *(this->self()); \
636 } \
637 \
638private: \
639 std::vector<::gko::deferred_factory_parameter<_name##_type>> \
640 _name##_generator_; \
641 \
642public: \
643 static_assert(true, \
644 "This assert is used to counter the false positive extra " \
645 "semi-colon warnings")
646
647
648} // namespace gko
649
650
651#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:75
std::unique_ptr< abstract_product_type > generate(Args &&... args) const
Creates a new product from the given components.
Definition abstract_factory.hpp:95
This mixin inherits from (a subclass of) PolymorphicObject and provides a base implementation of a ne...
Definition polymorphic_object.hpp:374
This mixin provides a default implementation of a concrete factory.
Definition abstract_factory.hpp:154
static parameters_type create()
Creates a new ParametersType object which can be used to instantiate a new ConcreteFactory.
Definition abstract_factory.hpp:196
const parameters_type & get_parameters() const noexcept
Returns the parameters of the factory.
Definition abstract_factory.hpp:179
This mixin is used to enable a default PolymorphicObject::copy_from() implementation for objects that...
Definition polymorphic_object.hpp:752
This mixin inherits from (a subclass of) PolymorphicObject and provides a base implementation of a ne...
Definition polymorphic_object.hpp:691
Represents a factory parameter of factory type that can either initialized by a pre-existing factory ...
Definition abstract_factory.hpp:337
std::shared_ptr< FactoryType > on(std::shared_ptr< const Executor > exec) const
Instantiates the deferred parameter into an actual factory.
Definition abstract_factory.hpp:397
bool is_empty() const
Returns true iff the parameter is empty.
Definition abstract_factory.hpp:406
deferred_factory_parameter(std::shared_ptr< ConcreteFactoryType > factory)
Creates a deferred factory parameter from a preexisting factory with shared ownership.
Definition abstract_factory.hpp:355
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:343
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:369
deferred_factory_parameter(ParametersType parameters)
Creates a deferred factory parameter object from a factory_parameters-like object.
Definition abstract_factory.hpp:387
The enable_parameters_type mixin is used to create a base implementation of the factory parameters st...
Definition abstract_factory.hpp:239
std::unique_ptr< Factory > on(std::shared_ptr< const Executor > exec) const
Creates a new factory on the specified executor.
Definition abstract_factory.hpp:261
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:248
The Ginkgo namespace.
Definition abstract_factory.hpp:48
constexpr T one()
Returns the multiplicative identity for T.
Definition math.hpp:803