aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/binsaver/class_factory.h
blob: f01f2c33a3c59bbc7dd496196f069cacbe2e4f5c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#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);