• Skip to content
  • Skip to link menu
KDE 4.4 API Reference
  • KDE API Reference
  • KDevelop Platform Libraries
  • Sitemap
  • Contact Us
 

language/duchain

codemodel.cpp

00001 /* This file is part of KDevelop
00002     Copyright 2008 David Nolden <david.nolden.kdevelop@art-master.de>
00003 
00004    This library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Library General Public
00006    License version 2 as published by the Free Software Foundation.
00007 
00008    This library is distributed in the hope that it will be useful,
00009    but WITHOUT ANY WARRANTY; without even the implied warranty of
00010    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00011    Library General Public License for more details.
00012 
00013    You should have received a copy of the GNU Library General Public License
00014    along with this library; see the file COPYING.LIB.  If not, write to
00015    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00016    Boston, MA 02110-1301, USA.
00017 */
00018 
00019 #include "codemodel.h"
00020 
00021 #include <QHash>
00022 #include <QVector>
00023 
00024 #include "appendedlist.h"
00025 #include "repositories/itemrepository.h"
00026 #include "identifier.h"
00027 #include "indexedstring.h"
00028 #include <util/embeddedfreetree.h>
00029 #include "referencecounting.h"
00030 
00031 #define ifDebug(x)
00032 
00033 namespace KDevelop {
00034 
00035 class CodeModelItemHandler {
00036     public:
00037     static int leftChild(const CodeModelItem& m_data) {
00038         return (int)m_data.referenceCount;
00039     }
00040     static void setLeftChild(CodeModelItem& m_data, int child) {
00041         m_data.referenceCount = (uint)child;
00042     }
00043     static int rightChild(const CodeModelItem& m_data) {
00044         return (int)m_data.uKind;
00045     }
00046     static void setRightChild(CodeModelItem& m_data, int child) {
00047         m_data.uKind = (uint)child;
00048     }
00049     //Copies this item into the given one
00050     static void copyTo(const CodeModelItem& m_data, CodeModelItem& data) {
00051       data = m_data;
00052     }
00053     
00054     static void createFreeItem(CodeModelItem& data) {
00055         data = CodeModelItem();
00056         data.referenceCount = (uint)-1;
00057         data.uKind = (uint)-1;
00058     }
00059     
00060     static bool isFree(const CodeModelItem& m_data) {
00061         return !m_data.id.isValid();
00062     }
00063 
00064     static const CodeModelItem& data(const CodeModelItem& m_data) {
00065       return m_data;
00066     }
00067     
00068     static bool equals(const CodeModelItem& m_data, const CodeModelItem& rhs) {
00069       return m_data.id == rhs.id;
00070     }
00071 };
00072 
00073 
00074 DEFINE_LIST_MEMBER_HASH(CodeModelRepositoryItem, items, CodeModelItem)
00075 
00076 class CodeModelRepositoryItem {
00077   public:
00078   CodeModelRepositoryItem() : centralFreeItem(-1) {
00079     initializeAppendedLists();
00080   }
00081   CodeModelRepositoryItem(const CodeModelRepositoryItem& rhs, bool dynamic = true) : file(rhs.file), centralFreeItem(rhs.centralFreeItem) {
00082     initializeAppendedLists(dynamic);
00083     copyListsFrom(rhs);
00084   }
00085   
00086   ~CodeModelRepositoryItem() {
00087     freeAppendedLists();
00088   }
00089   
00090   unsigned int hash() const {
00091     //We only compare the declaration. This allows us implementing a map, although the item-repository
00092     //originally represents a set.
00093     return file.index();
00094   }
00095   
00096   size_t itemSize() const {
00097     return dynamicSize();
00098   }
00099   
00100   uint classSize() const {
00101     return sizeof(CodeModelRepositoryItem);
00102   }
00103   
00104   IndexedString file;
00105   int centralFreeItem;
00106   
00107   START_APPENDED_LISTS(CodeModelRepositoryItem);
00108   APPENDED_LIST_FIRST(CodeModelRepositoryItem, CodeModelItem, items);
00109   END_APPENDED_LISTS(CodeModelRepositoryItem, items);
00110 };
00111 
00112 class CodeModelRequestItem {
00113   public:
00114   
00115   CodeModelRequestItem(const CodeModelRepositoryItem& item) : m_item(item) {
00116   }
00117   enum {
00118     AverageSize = 30 //This should be the approximate average size of an Item
00119   };
00120 
00121   unsigned int hash() const {
00122     return m_item.hash();
00123   }
00124   
00125   size_t itemSize() const {
00126       return m_item.itemSize();
00127   }
00128 
00129   void createItem(CodeModelRepositoryItem* item) const {
00130     Q_ASSERT(shouldDoDUChainReferenceCounting(item));
00131     Q_ASSERT(shouldDoDUChainReferenceCounting(((char*)item) + (itemSize()-1)));
00132     new (item) CodeModelRepositoryItem(m_item, false);
00133   }
00134   
00135   static void destroy(CodeModelRepositoryItem* item, KDevelop::AbstractItemRepository&) {
00136     Q_ASSERT(shouldDoDUChainReferenceCounting(item));
00137 //     Q_ASSERT(shouldDoDUChainReferenceCounting(((char*)item) + (itemSize()-1)));
00138     item->~CodeModelRepositoryItem();
00139   }
00140   
00141   static bool persistent(const CodeModelRepositoryItem* item) {
00142     Q_UNUSED(item);
00143     return true;
00144   }
00145   
00146   bool equals(const CodeModelRepositoryItem* item) const {
00147     return m_item.file == item->file;
00148   }
00149   
00150   const CodeModelRepositoryItem& m_item;
00151 };
00152 
00153 
00154 class CodeModelPrivate {
00155 public:
00156 
00157   CodeModelPrivate() : m_repository("Code Model") {
00158   }
00159   //Maps declaration-ids to items
00160   ItemRepository<CodeModelRepositoryItem, CodeModelRequestItem> m_repository;
00161 };
00162 
00163 CodeModel::CodeModel() : d(new CodeModelPrivate())
00164 {
00165 }
00166 
00167 CodeModel::~CodeModel()
00168 {
00169   delete d;
00170 }
00171 
00172 void CodeModel::addItem(const IndexedString& file, const IndexedQualifiedIdentifier& id, CodeModelItem::Kind kind)
00173 {
00174   ifDebug( kDebug() << "addItem" << file.str() << id.identifier().toString() << id.index; )
00175     
00176   if(!id.isValid())
00177     return;
00178   CodeModelRepositoryItem item;
00179   item.file = file;
00180   CodeModelRequestItem request(item);
00181   
00182   uint index = d->m_repository.findIndex(item);
00183   
00184   CodeModelItem newItem;
00185   newItem.id = id;
00186   newItem.kind = kind;
00187   newItem.referenceCount = 1;
00188   
00189   #ifdef TEST_REFERENCE_COUNTING_2
00190   {
00191   uint count = 0;
00192   const CodeModelItem* i;
00193   this->items(file, count, i);
00194   for(int a = 0; a < count; ++a)
00195     Q_ASSERT(i[a].id.hasReferenceCount());
00196   }
00197   #endif
00198   
00199   if(index) {
00200     const CodeModelRepositoryItem* oldItem = d->m_repository.itemFromIndex(index);
00201     EmbeddedTreeAlgorithms<CodeModelItem, CodeModelItemHandler> alg(oldItem->items(), oldItem->itemsSize(), oldItem->centralFreeItem);
00202     
00203     int listIndex = alg.indexOf(newItem);
00204     
00205     QMutexLocker lock(d->m_repository.mutex());
00206     
00207     DynamicItem<CodeModelRepositoryItem, true> editableItem = d->m_repository.dynamicItemFromIndex(index);
00208     CodeModelItem* items = const_cast<CodeModelItem*>(editableItem->items());
00209     
00210     if(listIndex != -1) {
00211       //Only update the reference-count
00212         ++items[listIndex].referenceCount;
00213         items[listIndex].kind = kind;
00214         return;
00215     }else{
00216       //Add the item to the list
00217       EmbeddedTreeAddItem<CodeModelItem, CodeModelItemHandler> add(items, editableItem->itemsSize(), editableItem->centralFreeItem, newItem);
00218       
00219       if(add.newItemCount() != editableItem->itemsSize()) {
00220         //The data needs to be transferred into a bigger list. That list is within "item".
00221         
00222         item.itemsList().resize(add.newItemCount());
00223         add.transferData(item.itemsList().data(), item.itemsList().size(), &item.centralFreeItem);
00224         
00225         d->m_repository.deleteItem(index);
00226       }else{
00227         //We're fine: The item fits into the existing list.
00228 #ifdef TEST_REFERENCE_COUNTING_2
00229         {
00230         uint count = 0;
00231         const CodeModelItem* i;
00232         this->items(file, count, i);
00233         for(int a = 0; a < count; ++a)
00234           Q_ASSERT(i[a].id.hasReferenceCount());
00235         }
00236 #endif
00237         return;
00238       }
00239     }
00240   }else{
00241     //We're creating a new index
00242     item.itemsList().append(newItem);
00243   }
00244 
00245 #ifdef TEST_REFERENCE_COUNTING_2
00246   {
00247   uint count = 0;
00248   const CodeModelItem* i;
00249   this->items(file, count, i);
00250   for(int a = 0; a < count; ++a)
00251     Q_ASSERT(i[a].id.hasReferenceCount());
00252   }
00253 #endif
00254 
00255   Q_ASSERT(!d->m_repository.findIndex(request));
00256 
00257   //This inserts the changed item
00258   volatile uint newIndex = d->m_repository.index(request);
00259   Q_UNUSED(newIndex);
00260   ifDebug( kDebug() << "new index" << newIndex; )
00261   
00262 #ifdef TEST_REFERENCE_COUNTING_2
00263   {
00264   uint count = 0;
00265   const CodeModelItem* i;
00266   this->items(file, count, i);
00267   for(int a = 0; a < count; ++a)
00268     Q_ASSERT(i[a].id.hasReferenceCount());
00269   }
00270 #endif
00271   
00272   Q_ASSERT(d->m_repository.findIndex(request));
00273 }
00274 
00275 void CodeModel::updateItem(const IndexedString& file, const IndexedQualifiedIdentifier& id, CodeModelItem::Kind kind)
00276 {
00277   ifDebug( kDebug() << file.str() << id.identifier().toString() << kind; )
00278     
00279   if(!id.isValid())
00280     return;
00281 
00282 #ifdef TEST_REFERENCE_COUNTING_2
00283   {
00284   uint count = 0;
00285   const CodeModelItem* i;
00286   this->items(file, count, i);
00287   for(int a = 0; a < count; ++a)
00288     Q_ASSERT(i[a].id.hasReferenceCount());
00289   }
00290 #endif
00291   
00292   CodeModelRepositoryItem item;
00293   item.file = file;
00294   CodeModelRequestItem request(item);
00295   
00296   CodeModelItem newItem;
00297   newItem.id = id;
00298   newItem.kind = kind;
00299   newItem.referenceCount = 1;
00300   
00301   uint index = d->m_repository.findIndex(item);
00302   
00303   if(index) {
00304     //Check whether the item is already in the mapped list, else copy the list into the new created item
00305     QMutexLocker lock(d->m_repository.mutex());
00306     DynamicItem<CodeModelRepositoryItem, true> oldItem = d->m_repository.dynamicItemFromIndex(index);
00307     
00308     EmbeddedTreeAlgorithms<CodeModelItem, CodeModelItemHandler> alg(oldItem->items(), oldItem->itemsSize(), oldItem->centralFreeItem);
00309     int listIndex = alg.indexOf(newItem);
00310     Q_ASSERT(listIndex != -1);
00311     
00312     CodeModelItem* items = const_cast<CodeModelItem*>(oldItem->items());
00313     
00314     Q_ASSERT(items[listIndex].id == id);
00315     items[listIndex].kind = kind;
00316     
00317 #ifdef TEST_REFERENCE_COUNTING_2
00318     {
00319     uint count = 0;
00320     const CodeModelItem* i;
00321     this->items(file, count, i);
00322     for(int a = 0; a < count; ++a)
00323       Q_ASSERT(i[a].id.hasReferenceCount());
00324     }
00325 #endif
00326     
00327     return;
00328   }
00329   
00330   Q_ASSERT(0); //The updated item as not in the symbol table!
00331 }
00332 
00333 void CodeModel::removeItem(const IndexedString& file, const IndexedQualifiedIdentifier& id)
00334 //void CodeModel::removeDeclaration(const QualifiedIdentifier& id, const IndexedDeclaration& declaration)
00335 {
00336   if(!id.isValid())
00337     return;
00338 #ifdef TEST_REFERENCE_COUNTING_2
00339   {
00340   uint count = 0;
00341   const CodeModelItem* i;
00342   this->items(file, count, i);
00343   for(int a = 0; a < count; ++a)
00344     Q_ASSERT(i[a].id.hasReferenceCount());
00345   }
00346 #endif  
00347   ifDebug( kDebug() << "removeItem" << file.str() << id.identifier().toString(); )
00348   CodeModelRepositoryItem item;
00349   item.file = file;
00350   CodeModelRequestItem request(item);
00351   
00352   uint index = d->m_repository.findIndex(item);
00353   
00354   if(index) {
00355     
00356     CodeModelItem searchItem;
00357     searchItem.id = id;
00358     
00359     QMutexLocker lock(d->m_repository.mutex());
00360     DynamicItem<CodeModelRepositoryItem, true> oldItem = d->m_repository.dynamicItemFromIndex(index);
00361     
00362     EmbeddedTreeAlgorithms<CodeModelItem, CodeModelItemHandler> alg(oldItem->items(), oldItem->itemsSize(), oldItem->centralFreeItem);
00363     
00364     int listIndex = alg.indexOf(searchItem);
00365     if(listIndex == -1)
00366       return;
00367     
00368     CodeModelItem* items = const_cast<CodeModelItem*>(oldItem->items());
00369     
00370     --items[listIndex].referenceCount;
00371     
00372     if(oldItem->items()[listIndex].referenceCount)
00373       return; //Nothing to remove, there's still a reference-count left
00374     
00375     //We have reduced the reference-count to zero, so remove the item from the list
00376     
00377     EmbeddedTreeRemoveItem<CodeModelItem, CodeModelItemHandler> remove(items, oldItem->itemsSize(), oldItem->centralFreeItem, searchItem);
00378     
00379     uint newItemCount = remove.newItemCount();
00380     if(newItemCount != oldItem->itemsSize()) {
00381       if(newItemCount == 0) {
00382         //Has become empty, delete the item
00383         d->m_repository.deleteItem(index);
00384 #ifdef TEST_REFERENCE_COUNTING_2
00385   {
00386   uint count = 0;
00387   const CodeModelItem* i;
00388   this->items(file, count, i);
00389   for(int a = 0; a < count; ++a)
00390     Q_ASSERT(i[a].id.hasReferenceCount());
00391   }
00392 #endif
00393         
00394         return;
00395       }else{
00396         //Make smaller
00397         item.itemsList().resize(newItemCount);
00398         remove.transferData(item.itemsList().data(), item.itemsSize(), &item.centralFreeItem);
00399         
00400         //Delete the old list
00401         d->m_repository.deleteItem(index);
00402         //Add the new list
00403         d->m_repository.index(request);
00404 #ifdef TEST_REFERENCE_COUNTING_2
00405   {
00406   uint count = 0;
00407   const CodeModelItem* i;
00408   this->items(file, count, i);
00409   for(int a = 0; a < count; ++a)
00410     Q_ASSERT(i[a].id.hasReferenceCount());
00411   }
00412 #endif
00413         return;
00414       }
00415     }
00416   }
00417 #ifdef TEST_REFERENCE_COUNTING_2
00418   {
00419   uint count = 0;
00420   const CodeModelItem* i;
00421   this->items(file, count, i);
00422   for(int a = 0; a < count; ++a)
00423     Q_ASSERT(i[a].id.hasReferenceCount());
00424   }
00425 #endif
00426 }
00427 
00428 void CodeModel::items(const IndexedString& file, uint& count, const CodeModelItem*& items) const
00429 {
00430   ifDebug( kDebug() << "items" << file.str(); )
00431 
00432   CodeModelRepositoryItem item;
00433   item.file = file;
00434   CodeModelRequestItem request(item);
00435   
00436   uint index = d->m_repository.findIndex(item);
00437   
00438   if(index) {
00439     const CodeModelRepositoryItem* repositoryItem = d->m_repository.itemFromIndex(index);
00440     ifDebug( kDebug() << "found index" << index << repositoryItem->itemsSize(); )
00441     count = repositoryItem->itemsSize();
00442     items = repositoryItem->items();
00443   }else{
00444     ifDebug( kDebug() << "found no index"; )
00445     count = 0;
00446     items = 0;
00447   }
00448 }
00449 
00450 CodeModel& CodeModel::self() {
00451   static CodeModel ret;
00452   return ret;
00453 }
00454 
00455 }
00456 

language/duchain

Skip menu "language/duchain"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

KDevelop Platform Libraries

Skip menu "KDevelop Platform Libraries"
  • interfaces
  • language
  •   codegen
  •   duchain
  •   editor
  • outputview
  • project
  • shell
  • sublime
  • util
  • vcs
Generated for KDevelop Platform Libraries by doxygen 1.5.9-20090814
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal