123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185 |
- #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...>;
- }
|