#pragma once #include #include #include #include #include #include namespace NObjectFactory { template class IFactoryObjectCreator { public: virtual TProduct* Create(TArgs... args) const = 0; virtual ~IFactoryObjectCreator() { } }; template class IFactoryObjectCreator { 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 TFactoryObjectCreator: public IFactoryObjectCreator { TDerivedProduct* Create(TArgs... args) const override { return new TDerivedProduct(std::forward(args)...); } }; template class TFactoryObjectCreator: public IFactoryObjectCreator { TDerivedProduct* Create() const override { return new TDerivedProduct(); } }; template class IObjectFactory { public: typedef P TProduct; typedef K TKey; public: template void Register(const TKey& key, IFactoryObjectCreator* 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 void Register(const TKey& key) { Register(key, new TFactoryObjectCreator); } void GetKeys(TSet& 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 IFactoryObjectCreator* 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 bool HasImpl(const T& key) const { TReadGuard guard(CreatorsLock); return Creators.find(key) != Creators.end(); } private: typedef TSimpleSharedPtr> ICreatorPtr; typedef TMap ICreators; ICreators Creators; TRWMutex CreatorsLock; }; template class TParametrizedObjectFactory: public IObjectFactory { public: template TProduct* Create(const T& key, TArgs... args) const { IFactoryObjectCreator* creator = IObjectFactory::GetCreator(key); return creator == nullptr ? nullptr : creator->Create(std::forward(args)...); } template static bool Has(const T& key) { return Singleton>()->HasImpl(key); } template static TProduct* Construct(const T& key, const TKey& defKey, TArgs... args) { TProduct* result = Singleton>()->Create(key, std::forward(args)...); if (!result && !!defKey) { result = Singleton>()->Create(defKey, std::forward(args)...); } return result; } template static TProduct* Construct(const T& key, TArgs... args) { return Singleton>()->Create(key, std::forward(args)...); } template static THolder VerifiedConstruct(Args&&... args) { auto result = MakeHolder(std::forward(args)...); Y_ABORT_UNLESS(result, "Construct by factory failed"); return result; } template static THolder MakeHolder(Args&&... args) { return THolder(Construct(std::forward(args)...)); } static void GetRegisteredKeys(TSet& keys) { return Singleton>()->GetKeys(keys); } static TSet GetRegisteredKeys() { TSet keys; Singleton>()->GetKeys(keys); return keys; } template static TSet GetRegisteredKeys() { TSet registeredKeys(GetRegisteredKeys()); TSet fileredKeys; std::copy_if(registeredKeys.begin(), registeredKeys.end(), std::inserter(fileredKeys, fileredKeys.end()), [](const TKey& key) { THolder objectHolder(Construct(key)); return !!dynamic_cast(objectHolder.Get()); }); return fileredKeys; } template class TRegistrator { public: TRegistrator(const TKey& key, IFactoryObjectCreator* creator) { Singleton>()->template Register(key, creator); } TRegistrator(const TKey& key) { Singleton>()->template Register(key); } TRegistrator() : TRegistrator(Product::GetTypeName()) { } TString GetName() const { return Product::GetTypeName(); } }; }; template using TObjectFactory = TParametrizedObjectFactory; }