File indexing completed on 2024-05-12 04:38:05

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 "uses.h"
0008 
0009 #include "declarationid.h"
0010 #include "duchainpointer.h"
0011 #include "serialization/itemrepository.h"
0012 #include "topducontext.h"
0013 
0014 namespace KDevelop {
0015 DEFINE_LIST_MEMBER_HASH(UsesItem, uses, IndexedTopDUContext)
0016 
0017 class UsesItem
0018 {
0019 public:
0020     UsesItem()
0021     {
0022         initializeAppendedLists();
0023     }
0024     UsesItem(const UsesItem& rhs, bool dynamic = true) : declaration(rhs.declaration)
0025     {
0026         initializeAppendedLists(dynamic);
0027         copyListsFrom(rhs);
0028     }
0029 
0030     ~UsesItem()
0031     {
0032         freeAppendedLists();
0033     }
0034 
0035     UsesItem& operator=(const UsesItem& rhs) = delete;
0036 
0037     unsigned int hash() const
0038     {
0039         //We only compare the declaration. This allows us implementing a map, although the item-repository
0040         //originally represents a set.
0041         return declaration.hash();
0042     }
0043 
0044     unsigned int itemSize() const
0045     {
0046         return dynamicSize();
0047     }
0048 
0049     uint classSize() const
0050     {
0051         return sizeof(UsesItem);
0052     }
0053 
0054     DeclarationId declaration;
0055 
0056     START_APPENDED_LISTS(UsesItem);
0057     APPENDED_LIST_FIRST(UsesItem, IndexedTopDUContext, uses);
0058     END_APPENDED_LISTS(UsesItem, uses);
0059 };
0060 
0061 class UsesRequestItem
0062 {
0063 public:
0064 
0065     UsesRequestItem(const UsesItem& item) : m_item(item)
0066     {
0067     }
0068     enum {
0069         AverageSize = 30 //This should be the approximate average size of an Item
0070     };
0071 
0072     unsigned int hash() const
0073     {
0074         return m_item.hash();
0075     }
0076 
0077     uint itemSize() const
0078     {
0079         return m_item.itemSize();
0080     }
0081 
0082     void createItem(UsesItem* item) const
0083     {
0084         new (item) UsesItem(m_item, false);
0085     }
0086 
0087     static void destroy(UsesItem* item, KDevelop::AbstractItemRepository&)
0088     {
0089         item->~UsesItem();
0090     }
0091 
0092     static bool persistent(const UsesItem* /*item*/)
0093     {
0094         return true;
0095     }
0096 
0097     bool equals(const UsesItem* item) const
0098     {
0099         return m_item.declaration == item->declaration;
0100     }
0101 
0102     const UsesItem& m_item;
0103 };
0104 
0105 // Maps declaration-ids to Uses
0106 using UsesRepo = ItemRepository<UsesItem, UsesRequestItem>;
0107 template<>
0108 class ItemRepositoryFor<Uses>
0109 {
0110     friend struct LockedItemRepository;
0111     static UsesRepo& repo()
0112     {
0113         static QMutex mutex;
0114         static UsesRepo repo { QStringLiteral("Use Map"), &mutex };
0115         return repo;
0116     }
0117 };
0118 
0119 Uses::Uses()
0120 {
0121     LockedItemRepository::initialize<Uses>();
0122 }
0123 
0124 void Uses::addUse(const DeclarationId& id, const IndexedTopDUContext& use)
0125 {
0126     UsesItem item;
0127     item.declaration = id;
0128     item.usesList().append(use);
0129     UsesRequestItem request(item);
0130 
0131     LockedItemRepository::write<Uses>([&](UsesRepo& repo) {
0132         uint index = repo.findIndex(item);
0133 
0134         if (index) {
0135             // Check whether the item is already in the mapped list, else copy the list into the new created item
0136             const UsesItem* oldItem = repo.itemFromIndex(index);
0137             for (unsigned int a = 0; a < oldItem->usesSize(); ++a) {
0138                 if (oldItem->uses()[a] == use)
0139                     return; // Already there
0140                 item.usesList().append(oldItem->uses()[a]);
0141             }
0142 
0143             repo.deleteItem(index);
0144         }
0145 
0146         // This inserts the changed item
0147         repo.index(request);
0148     });
0149 }
0150 
0151 void Uses::removeUse(const DeclarationId& id, const IndexedTopDUContext& use)
0152 {
0153     UsesItem item;
0154     item.declaration = id;
0155     UsesRequestItem request(item);
0156 
0157     LockedItemRepository::write<Uses>([&](UsesRepo& repo) {
0158         uint index = repo.findIndex(item);
0159 
0160         if (index) {
0161             // Check whether the item is already in the mapped list, else copy the list into the new created item
0162             const UsesItem* oldItem = repo.itemFromIndex(index);
0163             for (unsigned int a = 0; a < oldItem->usesSize(); ++a)
0164                 if (!(oldItem->uses()[a] == use))
0165                     item.usesList().append(oldItem->uses()[a]);
0166 
0167             repo.deleteItem(index);
0168             Q_ASSERT(repo.findIndex(item) == 0);
0169 
0170             // This inserts the changed item
0171             if (item.usesSize() != 0)
0172                 repo.index(request);
0173         }
0174     });
0175 }
0176 
0177 bool Uses::hasUses(const DeclarationId& id) const
0178 {
0179     UsesItem item;
0180     item.declaration = id;
0181 
0182     return LockedItemRepository::read<Uses>([&item](const UsesRepo& repo) {
0183         return static_cast<bool>(repo.findIndex(item));
0184     });
0185 }
0186 
0187 KDevVarLengthArray<IndexedTopDUContext> Uses::uses(const DeclarationId& id) const
0188 {
0189     KDevVarLengthArray<IndexedTopDUContext> ret;
0190 
0191     UsesItem item;
0192     item.declaration = id;
0193     UsesRequestItem request(item);
0194 
0195     LockedItemRepository::read<Uses>([&](const UsesRepo& repo) {
0196         uint index = repo.findIndex(item);
0197 
0198         if (index) {
0199             const UsesItem* repositoryItem = repo.itemFromIndex(index);
0200             FOREACH_FUNCTION(const IndexedTopDUContext& decl, repositoryItem->uses)
0201             ret.append(decl);
0202         }
0203     });
0204 
0205     return ret;
0206 }
0207 }