#pragma once #include #include #include #include //////////////////////////////////////////////////////////////////////////////////////////////////// // factory is using RTTI // objects should inherit T and T must have at least 1 virtual function template class TClassFactory { public: typedef const std::type_info* VFT; private: typedef T* (*newFunc)(); typedef THashMap CTypeNewHash; // typeID->newFunc() typedef THashMap 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 void RegisterType(int nTypeID, newFunc func, TT*) { RegisterTypeBase(nTypeID, func, &typeid(TT)); } void RegisterTypeSafe(int nTypeID, newFunc func) { TPtr 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 int GetTypeID(TT* p = 0) { (void)p; return VFT2TypeID(&typeid(TT)); } void GetAllTypeIDs(TVector& typeIds) const { typeIds.clear(); for (typename CTypeNewHash::const_iterator iter = typeInfo.begin(); iter != typeInfo.end(); ++iter) { typeIds.push_back(iter->first); } } }; //////////////////////////////////////////////////////////////////////////////////////////////////// template void TClassFactory::RegisterTypeBase(int nTypeID, newFunc func, VFT vft) { if (typeInfo.find(nTypeID) != typeInfo.end()) { TObj o1 = typeInfo[nTypeID](); TObj 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);