File indexing completed on 2024-06-16 04:23:17
0001 /* 0002 SPDX-FileCopyrightText: 2008 David Nolden <david.nolden.kdevelop@art-master.de> 0003 0004 SPDX-License-Identifier: LGPL-2.0-only 0005 */ 0006 0007 #ifndef KDEVPLATFORM_TYPEREGISTER_H 0008 #define KDEVPLATFORM_TYPEREGISTER_H 0009 0010 #include <QHash> 0011 0012 #include "abstracttype.h" 0013 #include "typesystemdata.h" 0014 0015 namespace KDevelop { 0016 /** 0017 * \short A factory class for type data. 0018 * 0019 * This class provides an interface for creating private data 0020 * structures for classes. 0021 */ 0022 class KDEVPLATFORMLANGUAGE_EXPORT AbstractTypeFactory 0023 { 0024 public: 0025 /** 0026 * Create a new type for the given \a data. 0027 * 0028 * \param data Data to assign to the new type. The data type must match the class type. 0029 */ 0030 virtual AbstractType* create(AbstractTypeData* data) const = 0; 0031 0032 /** 0033 * Call the destructor of the data-type. 0034 */ 0035 virtual void callDestructor(AbstractTypeData* data) const = 0; 0036 0037 /** 0038 * Copy contents of type-data \a from one location \a to another. 0039 * 0040 * \param from data to copy from 0041 * \param to data to copy to. This data must not be initialized yet 0042 * (the constructor must not have been called yet) 0043 * \param constant set to true if \a to is to be a static unchangeable 0044 * data type (eg. in the type-repository), or false if 0045 * \a to is to be a dynamic changeable type data. 0046 */ 0047 virtual void copy(const AbstractTypeData& from, AbstractTypeData& to, bool constant) const = 0; 0048 0049 /** 0050 * Return the memory size of the given private \a data, including dynamic data. 0051 * 0052 * \param data data structure 0053 * \returns the size in memory of the data. 0054 */ 0055 virtual uint dynamicSize(const AbstractTypeData& data) const = 0; 0056 0057 /// Destructor. 0058 virtual ~AbstractTypeFactory() 0059 { 0060 } 0061 }; 0062 0063 /** 0064 * Template class to implement factories for each AbstractType subclass you want 0065 * to instantiate. 0066 */ 0067 template <class T, class Data = typename T::Data> 0068 class TypeFactory 0069 : public AbstractTypeFactory 0070 { 0071 public: 0072 AbstractType* create(AbstractTypeData* data) const override 0073 { 0074 /* if(!m_reUseTypes.isEmpty()) { 0075 return new (m_reUseTypes.pop()) T(*static_cast<typename T::Data*>(data)); 0076 }else{*/ 0077 return new T(*static_cast<typename T::Data*>(data)); 0078 // } 0079 } 0080 0081 void copy(const AbstractTypeData& from, AbstractTypeData& to, bool constant) const override 0082 { 0083 Q_ASSERT(from.typeClassId == T::Identity); 0084 0085 if (( bool )from.m_dynamic == ( bool )!constant) { 0086 //We have a problem, "from" and "to" should both be either dynamic or constant. We must copy once more. 0087 Data* temp = &AbstractType::copyDataDirectly<Data>(static_cast<const Data&>(from)); 0088 0089 new (&to) Data(*temp); //Call the copy constructor to initialize the target 0090 0091 Q_ASSERT(( bool )to.m_dynamic == ( bool )!constant); 0092 destroyData(temp); 0093 } else { 0094 new (&to) Data(static_cast<const Data&>(from)); //Call the copy constructor to initialize the target 0095 } 0096 } 0097 0098 void destroyData(AbstractTypeData* data) const 0099 { 0100 callDestructor(data); 0101 delete[] ( char* )data; 0102 } 0103 0104 void callDestructor(AbstractTypeData* data) const override 0105 { 0106 Q_ASSERT(data->typeClassId == T::Identity); 0107 static_cast<Data*>(data)->~Data(); 0108 } 0109 0110 uint dynamicSize(const AbstractTypeData& data) const override 0111 { 0112 Q_ASSERT(data.typeClassId == T::Identity); 0113 return static_cast<const Data&>(data).dynamicSize(); 0114 } 0115 }; 0116 0117 /** 0118 * \short A class which registers data types and creates factories for them. 0119 * 0120 * TypeSystem is a global static class which allows you to register new 0121 * AbstractType subclasses for creation. 0122 */ 0123 class KDEVPLATFORMLANGUAGE_EXPORT TypeSystem 0124 { 0125 Q_DISABLE_COPY_MOVE(TypeSystem) 0126 TypeSystem() = default; 0127 public: 0128 /** 0129 * Register a new AbstractType subclass. 0130 */ 0131 template <class T, class Data = typename T::Data> 0132 void registerTypeClass() 0133 { 0134 registerTypeClassInternal(new TypeFactory<T, Data>(), sizeof(Data), T::Identity); 0135 } 0136 0137 /** 0138 * Unregister an AbstractType subclass. 0139 */ 0140 template <class T, class Data = typename T::Data> 0141 void unregisterTypeClass() 0142 { 0143 unregisterTypeClassInternal(T::Identity); 0144 } 0145 0146 /** 0147 * Create an AbstractType for the given data. The returned type must be put into a AbstractType::Ptr immediately. 0148 * Can return null if no type-factory is available for the given data (for example when a language-part is not loaded) 0149 */ 0150 AbstractType* create(AbstractTypeData* data) const; 0151 0152 /** 0153 * This just calls the correct constructor on the target. The target must be big enough to hold all the data. 0154 */ 0155 void copy(const AbstractTypeData& from, AbstractTypeData& to, bool constant) const; 0156 0157 ///Calls the dynamicSize(..) member on the given data, in the most special class. Since we cannot use virtual functions, this is the only way. 0158 uint dynamicSize(const AbstractTypeData& data) const; 0159 0160 ///Returns the size of the derived class, not including dynamic data. 0161 ///Returns zero if the class is not known. 0162 uint dataClassSize(const AbstractTypeData& data) const; 0163 0164 ///Calls the destructor, but does not delete anything. This is needed because the data classes must not contain virtual members. 0165 void callDestructor(AbstractTypeData* data) const; 0166 0167 ///Returns true if the factory for this data type is loaded. 0168 ///If false is returned, then any of the other calls will fail. 0169 bool isFactoryLoaded(const AbstractTypeData& data) const; 0170 0171 /// Access the static TypeSystem instance. 0172 static TypeSystem& self(); 0173 0174 private: 0175 void registerTypeClassInternal(AbstractTypeFactory* repo, uint dataClassSize, uint identity); 0176 void unregisterTypeClassInternal(uint identity); 0177 0178 bool ensureFactoryLoaded(const AbstractTypeData& data) const; 0179 0180 QHash<uint, AbstractTypeFactory*> m_factories; 0181 QHash<uint, uint> m_dataClassSizes; 0182 }; 0183 0184 /// Helper class to register an AbstractType subclass. 0185 /// 0186 /// Just use the REGISTER_TYPE(YourTypeClass) macro in your code, and you're done. 0187 template <class T, class Data = typename T::Data> 0188 struct TypeSystemRegistrator 0189 { 0190 TypeSystemRegistrator() 0191 { 0192 TypeSystem::self().registerTypeClass<T, Data>(); 0193 } 0194 ~TypeSystemRegistrator() 0195 { 0196 TypeSystem::self().unregisterTypeClass<T, Data>(); 0197 } 0198 private: 0199 Q_DISABLE_COPY(TypeSystemRegistrator) 0200 }; 0201 0202 ///You must add this into your source-files for every AbstractType based class 0203 ///For this to work, the class must have an "Identity" enumerator, that is unique among all types. 0204 ///It should be a unique value, but as small as possible, because a buffer at least as big as that number is created internally. 0205 #define REGISTER_TYPE(Class) TypeSystemRegistrator<Class, Class ## Data> register ## Class 0206 } 0207 0208 #endif