Last active
October 7, 2019 16:22
-
-
Save insaneyilin/2c9f5d883011402a6f6856afdafd6087 to your computer and use it in GitHub Desktop.
C++ class register factory
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright (c) 2019 Yilin Gui. All rights reserved. | |
// | |
// filename: register_factory.cpp | |
#include "./register_factory.h" | |
namespace register_factory { | |
BaseClassFactoryMap& GlobalBaseClassFactoryMap() { | |
static BaseClassFactoryMap base_factory_map; | |
return base_factory_map; | |
} | |
bool GetRegisteredDerivedClassNames( | |
const std::string &base_class_name, | |
std::vector<std::string> *registered_derived_class_names) { | |
if (!registered_derived_class_names) { | |
return false; | |
} | |
BaseClassFactoryMap &base_factory_map = GlobalBaseClassFactoryMap(); | |
auto iter = base_factory_map.find(base_class_name); | |
if (iter == base_factory_map.end()) { | |
std::cerr << "base class not registered: " << base_class_name << "\n"; | |
return false; | |
} | |
registered_derived_class_names->clear(); | |
for (auto pr : iter->second) { | |
registered_derived_class_names->push_back(pr.first); | |
} | |
return true; | |
} | |
} // namespace register_factory |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright (c) 2019 Yilin Gui. All rights reserved. | |
// | |
// filename: register_factory.h | |
// | |
// reference: | |
// modules/perception/lib/registerer/registerer.h from | |
// https://github.com/ApolloAuto/apollo | |
#ifndef REGISTER_FACTORY_H_ | |
#define REGISTER_FACTORY_H_ | |
#include <string> | |
#include <vector> | |
#include <unordered_map> | |
#include <iostream> | |
namespace register_factory { | |
class Any { | |
public: | |
Any() : holder_(nullptr) {} | |
template <typename ValueType> | |
Any(const ValueType &value) : holder_( | |
new PlaceHolder<ValueType>(value)) {} | |
Any(const Any &that) : holder_( | |
that.holder_ ? that.holder_->Clone() : nullptr) {} | |
~Any() { | |
delete holder_; | |
} | |
template <typename ValueType> | |
ValueType* AnyCast() { | |
return holder_ ? | |
&(static_cast<PlaceHolder<ValueType>*>(holder_)->value_) : nullptr; | |
} | |
private: | |
/// PlaceHolder interface | |
class IHolder { | |
public: | |
virtual ~IHolder() {} | |
virtual IHolder* Clone() const = 0; | |
}; | |
/// PlaceHolder | |
template <typename ValueType> | |
class PlaceHolder : public IHolder { | |
public: | |
explicit PlaceHolder(const ValueType &value) : value_(value) {} | |
virtual ~PlaceHolder() {} | |
virtual IHolder* Clone() const override { | |
return new PlaceHolder(value_); | |
} | |
public: | |
ValueType value_; | |
}; | |
private: | |
IHolder *holder_; | |
}; | |
class ObjectFactory { | |
public: | |
ObjectFactory() = default; | |
virtual ~ObjectFactory() {} | |
virtual Any NewInstance() { | |
return Any(); | |
} | |
ObjectFactory(const ObjectFactory &) = delete; | |
ObjectFactory &operator=(const ObjectFactory &) = delete; | |
}; | |
using ObjectFactoryMap = std::unordered_map<std::string, ObjectFactory*>; | |
using BaseClassFactoryMap = std::unordered_map<std::string, ObjectFactoryMap>; | |
BaseClassFactoryMap& GlobalBaseClassFactoryMap(); | |
bool GetRegisteredDerivedClassNames( | |
const std::string &base_class_name, | |
std::vector<std::string> *registered_derived_class_names); | |
} // namespace register_factory | |
#define REGISTER_BASE_CLASS_FACTORY(base_class) \ | |
class base_class##Factory { \ | |
using Any = ::register_factory::Any; \ | |
using ObjectFactoryMap = ::register_factory::ObjectFactoryMap; \ | |
public: \ | |
static base_class* GetInstancePtrByName(const std::string &name) { \ | |
ObjectFactoryMap &obj_factory_map = \ | |
::register_factory::GlobalBaseClassFactoryMap()[#base_class]; \ | |
auto iter = obj_factory_map.find(name); \ | |
if (iter == obj_factory_map.end()) { \ | |
std::cerr << "Get instance " << name << " failed.\n"; \ | |
return nullptr; \ | |
} \ | |
Any obj = iter->second->NewInstance(); \ | |
return *(obj.AnyCast<base_class*>()); \ | |
} \ | |
}; | |
#define REGISTER_SUB_CLASS_BY_NAME(base_class, sub_class_name) \ | |
namespace { \ | |
using Any = ::register_factory::Any; \ | |
using ObjectFactory = ::register_factory::ObjectFactory; \ | |
using ObjectFactoryMap = ::register_factory::ObjectFactoryMap; \ | |
class sub_class_name##ObjectFactory : public ObjectFactory { \ | |
public: \ | |
virtual ~sub_class_name##ObjectFactory() {} \ | |
virtual Any NewInstance() { \ | |
return Any(new sub_class_name()); \ | |
} \ | |
}; \ | |
__attribute__((constructor)) \ | |
void Register##sub_class_name##ObjectFactory() { \ | |
ObjectFactoryMap &obj_factory_map = \ | |
::register_factory::GlobalBaseClassFactoryMap()[#base_class]; \ | |
if (obj_factory_map.find(#sub_class_name) == obj_factory_map.end()) { \ | |
obj_factory_map[#sub_class_name] = new sub_class_name##ObjectFactory(); \ | |
} \ | |
} \ | |
} | |
#endif // REGISTER_FACTORY_H_ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
////////////////////////////////////////////// | |
// base_class.h | |
////////////////////////////////////////////// | |
#ifndef REGISTER_FACTORY_TEST_BASE_CLASS_H_ | |
#define REGISTER_FACTORY_TEST_BASE_CLASS_H_ | |
#include <string> | |
#include <iostream> | |
#include "register_factory/register_factory.h" | |
class BaseClass { | |
public: | |
BaseClass() = default; | |
virtual ~BaseClass() = default; | |
virtual std::string Name() const = 0; | |
virtual void PrintName() const = 0; | |
}; | |
REGISTER_BASE_CLASS_FACTORY(BaseClass); | |
#define REGISTER_BASE_CLASS_BY_NAME(sub_class_name) \ | |
REGISTER_SUB_CLASS_BY_NAME(BaseClass, sub_class_name) | |
#endif // REGISTER_FACTORY_TEST_BASE_CLASS_H_ | |
////////////////////////////////////////////// | |
// sub_classes.h | |
////////////////////////////////////////////// | |
#ifndef REGISTER_FACTORY_TEST_SUB_CLASSES_H_ | |
#define REGISTER_FACTORY_TEST_SUB_CLASSES_H_ | |
#include "base_class.h" | |
class SubClass1 : public BaseClass { | |
public: | |
virtual std::string Name() const override { | |
return "SubClass1"; | |
} | |
virtual void PrintName() const override { | |
std::cout << "I am " << Name() << std::endl; | |
} | |
}; | |
class SubClass2 : public BaseClass { | |
public: | |
virtual std::string Name() const override { | |
return "SubClass2"; | |
} | |
virtual void PrintName() const override { | |
std::cout << "I am " << Name() << std::endl; | |
} | |
}; | |
#endif // REGISTER_FACTORY_TEST_BASE_CLASS_H_ | |
////////////////////////////////////////////// | |
// sub_classes.cpp | |
////////////////////////////////////////////// | |
#include "sub_classes.h" | |
REGISTER_BASE_CLASS_BY_NAME(SubClass1); | |
REGISTER_BASE_CLASS_BY_NAME(SubClass2); | |
////////////////////////////////////////////// | |
// main.cpp | |
////////////////////////////////////////////// | |
#include <iostream> | |
#include <memory> | |
#include "register_factory/register_factory.h" | |
#include "base_class.h" | |
#include "sub_classes.h" | |
int main(int argc, char **argv) { | |
std::shared_ptr<BaseClass> p1(nullptr); | |
std::shared_ptr<BaseClass> p2(nullptr); | |
p1.reset(BaseClassFactory::GetInstancePtrByName("SubClass1")); | |
p1->PrintName(); | |
p2.reset(BaseClassFactory::GetInstancePtrByName("SubClass2")); | |
p2->PrintName(); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment