class_factory.h 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. #pragma once
  2. #include <typeinfo>
  3. #include <util/generic/hash.h>
  4. #include <util/generic/vector.h>
  5. #include <util/ysafeptr.h>
  6. ////////////////////////////////////////////////////////////////////////////////////////////////////
  7. // factory is using RTTI
  8. // objects should inherit T and T must have at least 1 virtual function
  9. template <class T>
  10. class TClassFactory {
  11. public:
  12. typedef const std::type_info* VFT;
  13. private:
  14. typedef T* (*newFunc)();
  15. typedef THashMap<int, newFunc> CTypeNewHash; // typeID->newFunc()
  16. typedef THashMap<VFT, int> CTypeIndexHash; // vftable->typeID
  17. CTypeIndexHash typeIndex;
  18. CTypeNewHash typeInfo;
  19. void RegisterTypeBase(int nTypeID, newFunc func, VFT vft);
  20. static VFT GetObjectType(T* pObject) {
  21. return &typeid(*pObject);
  22. }
  23. int VFT2TypeID(VFT t) {
  24. CTypeIndexHash::iterator i = typeIndex.find(t);
  25. if (i != typeIndex.end())
  26. return i->second;
  27. for (i = typeIndex.begin(); i != typeIndex.end(); ++i) {
  28. if (*i->first == *t) {
  29. typeIndex[t] = i->second;
  30. return i->second;
  31. }
  32. }
  33. return -1;
  34. }
  35. public:
  36. template <class TT>
  37. void RegisterType(int nTypeID, newFunc func, TT*) {
  38. RegisterTypeBase(nTypeID, func, &typeid(TT));
  39. }
  40. void RegisterTypeSafe(int nTypeID, newFunc func) {
  41. TPtr<T> pObj = func();
  42. VFT vft = GetObjectType(pObj);
  43. RegisterTypeBase(nTypeID, func, vft);
  44. }
  45. T* CreateObject(int nTypeID) {
  46. newFunc f = typeInfo[nTypeID];
  47. if (f)
  48. return f();
  49. return nullptr;
  50. }
  51. int GetObjectTypeID(T* pObject) {
  52. return VFT2TypeID(GetObjectType(pObject));
  53. }
  54. template <class TT>
  55. int GetTypeID(TT* p = 0) {
  56. (void)p;
  57. return VFT2TypeID(&typeid(TT));
  58. }
  59. void GetAllTypeIDs(TVector<int>& typeIds) const {
  60. typeIds.clear();
  61. for (typename CTypeNewHash::const_iterator iter = typeInfo.begin();
  62. iter != typeInfo.end();
  63. ++iter) {
  64. typeIds.push_back(iter->first);
  65. }
  66. }
  67. };
  68. ////////////////////////////////////////////////////////////////////////////////////////////////////
  69. template <class T>
  70. void TClassFactory<T>::RegisterTypeBase(int nTypeID, newFunc func, VFT vft) {
  71. if (typeInfo.find(nTypeID) != typeInfo.end()) {
  72. TObj<IObjectBase> o1 = typeInfo[nTypeID]();
  73. TObj<IObjectBase> o2 = func();
  74. // stupid clang warning
  75. auto& o1v = *o1;
  76. auto& o2v = *o2;
  77. if (typeid(o1v) != typeid(o2v)) {
  78. fprintf(stderr, "IBinSaver: Type ID 0x%08X has been already used\n", nTypeID);
  79. abort();
  80. }
  81. }
  82. CTypeIndexHash::iterator typeIndexIt = typeIndex.find(vft);
  83. if (typeIndexIt != typeIndex.end() && nTypeID != typeIndexIt->second) {
  84. fprintf(stderr, "IBinSaver: class (Type ID 0x%08X) has been already registered (Type ID 0x%08X)\n", nTypeID, typeIndexIt->second);
  85. abort();
  86. }
  87. typeIndex[vft] = nTypeID;
  88. typeInfo[nTypeID] = func;
  89. }
  90. ////////////////////////////////////////////////////////////////////////////////////////////////////
  91. // macro for registering CFundament derivatives
  92. #define REGISTER_CLASS(factory, N, name) factory.RegisterType(N, name::New##name, (name*)0);
  93. #define REGISTER_TEMPL_CLASS(factory, N, name, className) factory.RegisterType(N, name::New##className, (name*)0);
  94. #define REGISTER_CLASS_NM(factory, N, name, nmspace) factory.RegisterType(N, nmspace::name::New##name, (nmspace::name*)0);