Skip to content

Instantly share code, notes, and snippets.

@insaneyilin
Last active October 7, 2019 16:22
Show Gist options
  • Save insaneyilin/2c9f5d883011402a6f6856afdafd6087 to your computer and use it in GitHub Desktop.
Save insaneyilin/2c9f5d883011402a6f6856afdafd6087 to your computer and use it in GitHub Desktop.
C++ class register factory
// 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
// 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_
//////////////////////////////////////////////
// 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