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 #include "typerepository.h" 0008 0009 #include <QMutex> 0010 #include <QMutexLocker> 0011 0012 #include <debug.h> 0013 #include "../types/typesystemdata.h" 0014 #include "../types/typeregister.h" 0015 #include <serialization/referencecounting.h> 0016 #include <serialization/itemrepository.h> 0017 #include <serialization/repositorymanager.h> 0018 0019 #define DEBUG_TYPE_REPOSITORY 0020 #define ASSERT_ON_PROBLEM 0021 0022 namespace KDevelop { 0023 class AbstractTypeDataRequest 0024 { 0025 public: 0026 AbstractTypeDataRequest(const AbstractType& type) : m_item(type) 0027 { 0028 } 0029 0030 enum { 0031 AverageSize = sizeof(AbstractTypeData) + 12 0032 }; 0033 0034 unsigned int hash() const 0035 { 0036 return m_item.hash(); 0037 } 0038 0039 uint itemSize() const 0040 { 0041 return TypeSystem::self().dynamicSize(*m_item.d_ptr); 0042 } 0043 0044 void createItem(AbstractTypeData* item) const 0045 { 0046 TypeSystem::self().copy(*m_item.d_ptr, *item, true); 0047 Q_ASSERT(!item->m_dynamic); 0048 #ifdef DEBUG_TYPE_REPOSITORY 0049 AbstractType::Ptr otherType(TypeSystem::self().create(const_cast<AbstractTypeData*>(item))); 0050 if (!otherType->equals(&m_item)) { 0051 //For debugging, so one can trace what happened 0052 qCWarning(LANGUAGE) << "created type in repository does not equal source type:" << m_item.toString() << 0053 otherType->toString(); 0054 TypeSystem::self().copy(*m_item.d_ptr, *item, true); 0055 otherType->equals(&m_item); 0056 } 0057 #ifdef ASSERT_ON_PROBLEM 0058 Q_ASSERT(otherType->equals(&m_item)); 0059 #endif 0060 #endif 0061 item->inRepository = true; 0062 } 0063 0064 static void destroy(AbstractTypeData* item, KDevelop::AbstractItemRepository&) 0065 { 0066 TypeSystem::self().callDestructor(item); 0067 } 0068 0069 static bool persistent(const AbstractTypeData* item) 0070 { 0071 // Don't try to delete release items for which the factory is not loaded, as that will lead to a crash/assertion later 0072 return ( bool )item->refCount || !TypeSystem::self().isFactoryLoaded(*item); 0073 } 0074 0075 bool equals(const AbstractTypeData* item) const 0076 { 0077 if (!TypeSystem::self().isFactoryLoaded(*item)) 0078 return false; 0079 0080 AbstractType::Ptr otherType(TypeSystem::self().create(const_cast<AbstractTypeData*>(item))); 0081 Q_ASSERT(otherType); 0082 return m_item.equals(otherType.data()); 0083 } 0084 0085 const AbstractType& m_item; 0086 }; 0087 0088 QRecursiveMutex* typeRepositoryMutex() 0089 { 0090 static QRecursiveMutex mutex; 0091 return &mutex; 0092 } 0093 0094 using TypeItemRepository = ItemRepository<AbstractTypeData, AbstractTypeDataRequest, true, QRecursiveMutex>; 0095 0096 template<> 0097 class ItemRepositoryFor<AbstractType> 0098 { 0099 friend struct LockedItemRepository; 0100 static TypeItemRepository& repo() 0101 { 0102 static RepositoryManager<TypeItemRepository, false> manager(QStringLiteral("Type Repository"), 0103 typeRepositoryMutex()); 0104 return *manager.repository(); 0105 } 0106 }; 0107 0108 void initTypeRepository() 0109 { 0110 LockedItemRepository::initialize<AbstractType>(); 0111 } 0112 0113 uint TypeRepository::indexForType(const AbstractType* input) 0114 { 0115 if (!input) 0116 return 0; 0117 0118 uint i = LockedItemRepository::write<AbstractType>( 0119 [request = AbstractTypeDataRequest(*input)](TypeItemRepository& repo) { 0120 return repo.index(request); 0121 }); 0122 #ifdef DEBUG_TYPE_REPOSITORY 0123 AbstractType::Ptr t = typeForIndex(i); 0124 if (!t->equals(input)) { 0125 qCWarning(LANGUAGE) << "found type in repository does not equal source type:" << input->toString() << 0126 t->toString(); 0127 t->equals(input); 0128 } 0129 #ifdef ASSERT_ON_PROBLEM 0130 Q_ASSERT(t->equals(input)); 0131 Q_ASSERT(input->equals(t.data())); 0132 #endif 0133 #endif 0134 return i; 0135 } 0136 0137 AbstractType::Ptr TypeRepository::typeForIndex(uint index) 0138 { 0139 if (index == 0) 0140 return AbstractType::Ptr(); 0141 0142 return LockedItemRepository::read<AbstractType>([index](const TypeItemRepository& repo) { 0143 auto item = repo.itemFromIndex(index); 0144 return AbstractType::Ptr(TypeSystem::self().create(const_cast<AbstractTypeData*>(item))); 0145 }); 0146 } 0147 0148 template <typename RefCountChanger> 0149 static void changeReferenceCount(uint index, RefCountChanger changeRefCount) 0150 { 0151 if (!index) 0152 return; 0153 0154 LockedItemRepository::write<AbstractType>([index, changeRefCount](TypeItemRepository& repo) { 0155 AbstractTypeData* data = repo.dynamicItemFromIndexSimple(index); 0156 Q_ASSERT(data); 0157 changeRefCount(data->refCount); 0158 }); 0159 } 0160 0161 void TypeRepository::increaseReferenceCount(uint index, ReferenceCountManager* manager) 0162 { 0163 changeReferenceCount(index, [index, manager](uint& refCount) { 0164 if (manager) 0165 manager->increase(refCount, index); 0166 else 0167 ++refCount; 0168 }); 0169 } 0170 0171 void TypeRepository::decreaseReferenceCount(uint index, ReferenceCountManager* manager) 0172 { 0173 changeReferenceCount(index, [index, manager](uint& refCount) { 0174 Q_ASSERT(refCount > 0); 0175 if (manager) 0176 manager->decrease(refCount, index); 0177 else 0178 --refCount; 0179 }); 0180 } 0181 }