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 }