123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105 |
- #pragma once
- #include <typeinfo>
- #include <util/generic/hash.h>
- #include <util/generic/vector.h>
- #include <util/ysafeptr.h>
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- // factory is using RTTI
- // objects should inherit T and T must have at least 1 virtual function
- template <class T>
- class TClassFactory {
- public:
- typedef const std::type_info* VFT;
- private:
- typedef T* (*newFunc)();
- typedef THashMap<int, newFunc> CTypeNewHash; // typeID->newFunc()
- typedef THashMap<VFT, int> CTypeIndexHash; // vftable->typeID
- CTypeIndexHash typeIndex;
- CTypeNewHash typeInfo;
- void RegisterTypeBase(int nTypeID, newFunc func, VFT vft);
- static VFT GetObjectType(T* pObject) {
- return &typeid(*pObject);
- }
- int VFT2TypeID(VFT t) {
- CTypeIndexHash::iterator i = typeIndex.find(t);
- if (i != typeIndex.end())
- return i->second;
- for (i = typeIndex.begin(); i != typeIndex.end(); ++i) {
- if (*i->first == *t) {
- typeIndex[t] = i->second;
- return i->second;
- }
- }
- return -1;
- }
- public:
- template <class TT>
- void RegisterType(int nTypeID, newFunc func, TT*) {
- RegisterTypeBase(nTypeID, func, &typeid(TT));
- }
- void RegisterTypeSafe(int nTypeID, newFunc func) {
- TPtr<T> pObj = func();
- VFT vft = GetObjectType(pObj);
- RegisterTypeBase(nTypeID, func, vft);
- }
- T* CreateObject(int nTypeID) {
- newFunc f = typeInfo[nTypeID];
- if (f)
- return f();
- return nullptr;
- }
- int GetObjectTypeID(T* pObject) {
- return VFT2TypeID(GetObjectType(pObject));
- }
- template <class TT>
- int GetTypeID(TT* p = 0) {
- (void)p;
- return VFT2TypeID(&typeid(TT));
- }
- void GetAllTypeIDs(TVector<int>& typeIds) const {
- typeIds.clear();
- for (typename CTypeNewHash::const_iterator iter = typeInfo.begin();
- iter != typeInfo.end();
- ++iter) {
- typeIds.push_back(iter->first);
- }
- }
- };
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- template <class T>
- void TClassFactory<T>::RegisterTypeBase(int nTypeID, newFunc func, VFT vft) {
- if (typeInfo.find(nTypeID) != typeInfo.end()) {
- TObj<IObjectBase> o1 = typeInfo[nTypeID]();
- TObj<IObjectBase> o2 = func();
- // stupid clang warning
- auto& o1v = *o1;
- auto& o2v = *o2;
- if (typeid(o1v) != typeid(o2v)) {
- fprintf(stderr, "IBinSaver: Type ID 0x%08X has been already used\n", nTypeID);
- abort();
- }
- }
- CTypeIndexHash::iterator typeIndexIt = typeIndex.find(vft);
- if (typeIndexIt != typeIndex.end() && nTypeID != typeIndexIt->second) {
- fprintf(stderr, "IBinSaver: class (Type ID 0x%08X) has been already registered (Type ID 0x%08X)\n", nTypeID, typeIndexIt->second);
- abort();
- }
- typeIndex[vft] = nTypeID;
- typeInfo[nTypeID] = func;
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- // macro for registering CFundament derivatives
- #define REGISTER_CLASS(factory, N, name) factory.RegisterType(N, name::New##name, (name*)0);
- #define REGISTER_TEMPL_CLASS(factory, N, name, className) factory.RegisterType(N, name::New##className, (name*)0);
- #define REGISTER_CLASS_NM(factory, N, name, nmspace) factory.RegisterType(N, nmspace::name::New##name, (nmspace::name*)0);
|