#pragma once #include <util/system/guard.h> #include <util/system/rwlock.h> #include <util/generic/map.h> #include <util/generic/set.h> #include <util/generic/singleton.h> #include <util/generic/yexception.h> namespace NObjectFactory { template <class TProduct, class... TArgs> class IFactoryObjectCreator { public: virtual TProduct* Create(TArgs... args) const = 0; virtual ~IFactoryObjectCreator() { } }; template <class TProduct> class IFactoryObjectCreator<TProduct, void> { public: virtual TProduct* Create(void) const = 0; virtual ~IFactoryObjectCreator() { } }; #define FACTORY_OBJECT_NAME(Name) \ static TString GetTypeName() { \ return #Name; \ } \ virtual TString GetType() const override { \ return #Name; \ } template <class TBaseProduct, class TDerivedProduct, class... TArgs> class TFactoryObjectCreator: public IFactoryObjectCreator<TBaseProduct, TArgs...> { TDerivedProduct* Create(TArgs... args) const override { return new TDerivedProduct(std::forward<TArgs>(args)...); } }; template <class TBaseProduct, class TDerivedProduct> class TFactoryObjectCreator<TBaseProduct, TDerivedProduct, void>: public IFactoryObjectCreator<TBaseProduct, void> { TDerivedProduct* Create() const override { return new TDerivedProduct(); } }; template <class P, class K, class... TArgs> class IObjectFactory { public: typedef P TProduct; typedef K TKey; public: template <class TDerivedProduct> void Register(const TKey& key, IFactoryObjectCreator<TProduct, TArgs...>* creator) { if (!creator) ythrow yexception() << "Please specify non-null creator for " << key; TWriteGuard guard(CreatorsLock); if (!Creators.insert(typename ICreators::value_type(key, creator)).second) ythrow yexception() << "Product with key " << key << " already registered"; } template <class TDerivedProduct> void Register(const TKey& key) { Register<TDerivedProduct>(key, new TFactoryObjectCreator<TProduct, TDerivedProduct, TArgs...>); } void GetKeys(TSet<TKey>& keys) const { TReadGuard guard(CreatorsLock); keys.clear(); for (typename ICreators::const_iterator i = Creators.begin(), e = Creators.end(); i != e; ++i) { keys.insert(i->first); } } protected: template <class T> IFactoryObjectCreator<TProduct, TArgs...>* GetCreator(const T& key) const { TReadGuard guard(CreatorsLock); typename ICreators::const_iterator i = Creators.find(key); return i == Creators.end() ? nullptr : i->second.Get(); } template <class T> bool HasImpl(const T& key) const { TReadGuard guard(CreatorsLock); return Creators.find(key) != Creators.end(); } private: typedef TSimpleSharedPtr<IFactoryObjectCreator<TProduct, TArgs...>> ICreatorPtr; typedef TMap<TKey, ICreatorPtr> ICreators; ICreators Creators; TRWMutex CreatorsLock; }; template <class TProduct, class TKey, class... TArgs> class TParametrizedObjectFactory: public IObjectFactory<TProduct, TKey, TArgs...> { public: template <class T> TProduct* Create(const T& key, TArgs... args) const { IFactoryObjectCreator<TProduct, TArgs...>* creator = IObjectFactory<TProduct, TKey, TArgs...>::GetCreator(key); return creator == nullptr ? nullptr : creator->Create(std::forward<TArgs>(args)...); } template <class T> static bool Has(const T& key) { return Singleton<TParametrizedObjectFactory<TProduct, TKey, TArgs...>>()->HasImpl(key); } template <class T> static TProduct* Construct(const T& key, const TKey& defKey, TArgs... args) { TProduct* result = Singleton<TParametrizedObjectFactory<TProduct, TKey, TArgs...>>()->Create(key, std::forward<TArgs>(args)...); if (!result && !!defKey) { result = Singleton<TParametrizedObjectFactory<TProduct, TKey, TArgs...>>()->Create(defKey, std::forward<TArgs>(args)...); } return result; } template <class T> static TProduct* Construct(const T& key, TArgs... args) { return Singleton<TParametrizedObjectFactory<TProduct, TKey, TArgs...>>()->Create(key, std::forward<TArgs>(args)...); } template <class... Args> static THolder<TProduct> VerifiedConstruct(Args&&... args) { auto result = MakeHolder(std::forward<Args>(args)...); Y_ABORT_UNLESS(result, "Construct by factory failed"); return result; } template<class... Args> static THolder<TProduct> MakeHolder(Args&&... args) { return THolder<TProduct>(Construct(std::forward<Args>(args)...)); } static void GetRegisteredKeys(TSet<TKey>& keys) { return Singleton<TParametrizedObjectFactory<TProduct, TKey, TArgs...>>()->GetKeys(keys); } static TSet<TKey> GetRegisteredKeys() { TSet<TKey> keys; Singleton<TParametrizedObjectFactory<TProduct, TKey, TArgs...>>()->GetKeys(keys); return keys; } template <class TDerivedProduct> static TSet<TKey> GetRegisteredKeys() { TSet<TKey> registeredKeys(GetRegisteredKeys()); TSet<TKey> fileredKeys; std::copy_if(registeredKeys.begin(), registeredKeys.end(), std::inserter(fileredKeys, fileredKeys.end()), [](const TKey& key) { THolder<TProduct> objectHolder(Construct(key)); return !!dynamic_cast<const TDerivedProduct*>(objectHolder.Get()); }); return fileredKeys; } template <class Product> class TRegistrator { public: TRegistrator(const TKey& key, IFactoryObjectCreator<TProduct, TArgs...>* creator) { Singleton<TParametrizedObjectFactory<TProduct, TKey, TArgs...>>()->template Register<Product>(key, creator); } TRegistrator(const TKey& key) { Singleton<TParametrizedObjectFactory<TProduct, TKey, TArgs...>>()->template Register<Product>(key); } TRegistrator() : TRegistrator(Product::GetTypeName()) { } TString GetName() const { return Product::GetTypeName(); } }; }; template <class TProduct, class TKey, class... TArgs> using TObjectFactory = TParametrizedObjectFactory<TProduct, TKey, TArgs...>; }