1 /* This file is part of KDevelop
2 Copyright 2008 David Nolden <david.nolden.kdevelop@art-master.de>
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License version 2 as published by the Free Software Foundation.
8 This library is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 Library General Public License for more details.
13 You should have received a copy of the GNU Library General Public License
14 along with this library; see the file COPYING.LIB. If not, write to
15 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
16 Boston, MA 02110-1301, USA.
19 #include "codemodel.h"
24 #include "appendedlist.h"
25 #include "repositories/itemrepository.h"
26 #include "identifier.h"
27 #include "indexedstring.h"
33 DEFINE_LIST_MEMBER_HASH(CodeModelRepositoryItem
, items
, CodeModelItem
)
35 class CodeModelRepositoryItem
{
37 CodeModelRepositoryItem() {
38 initializeAppendedLists();
40 CodeModelRepositoryItem(const CodeModelRepositoryItem
& rhs
) : file(rhs
.file
) {
41 initializeAppendedLists();
45 ~CodeModelRepositoryItem() {
49 unsigned int hash() const {
50 //We only compare the declaration. This allows us implementing a map, although the item-repository
51 //originally represents a set.
55 unsigned short int itemSize() const {
59 uint
classSize() const {
60 return sizeof(CodeModelRepositoryItem
);
65 START_APPENDED_LISTS(CodeModelRepositoryItem
);
66 APPENDED_LIST_FIRST(CodeModelRepositoryItem
, CodeModelItem
, items
);
67 END_APPENDED_LISTS(CodeModelRepositoryItem
, items
);
70 class CodeModelRequestItem
{
73 CodeModelRequestItem(const CodeModelRepositoryItem
& item
) : m_item(item
) {
76 AverageSize
= 30 //This should be the approximate average size of an Item
79 unsigned int hash() const {
83 size_t itemSize() const {
84 return m_item
.itemSize();
87 void createItem(CodeModelRepositoryItem
* item
) const {
88 item
->initializeAppendedLists(false);
89 item
->file
= m_item
.file
;
90 item
->copyListsFrom(m_item
);
93 bool equals(const CodeModelRepositoryItem
* item
) const {
94 return m_item
.file
== item
->file
;
97 const CodeModelRepositoryItem
& m_item
;
101 struct CodeModelPrivate
{
102 CodeModelPrivate() : m_repository("Code Model") {
104 //Maps declaration-ids to items
105 ItemRepository
<CodeModelRepositoryItem
, CodeModelRequestItem
> m_repository
;
108 CodeModel::CodeModel() : d(new CodeModelPrivate())
112 CodeModel::~CodeModel()
117 ///@todo Sorting in the items list, so searches can be faster
118 void CodeModel::addItem(const IndexedString
& file
, const IndexedQualifiedIdentifier
& id
, CodeModelItem::Kind kind
)
120 ifDebug( kDebug() << "addItem" << file
.str() << id
.identifier().toString(); )
124 CodeModelRepositoryItem item
;
126 CodeModelRequestItem
request(item
);
128 uint index
= d
->m_repository
.findIndex(item
);
131 //Check whether the item is already in the mapped list, else copy the list into the new created item
132 const CodeModelRepositoryItem
* oldItem
= d
->m_repository
.itemFromIndex(index
);
133 ifDebug( kDebug() << "found index" << index
<< "count:" << oldItem
->itemsSize(); )
135 uint itemsSize
= oldItem
->itemsSize();
136 const KDevelop::CodeModelItem
* items
= oldItem
->items();
138 for(uint a
= 0; a
< itemsSize
; ++a
) {
139 ifDebug( kDebug() << "id at" << a
<< items
[a
].id
.identifier().toString(); )
140 if(items
[a
].id
== id
) {
141 CodeModelRepositoryItem
* editableItem
= d
->m_repository
.dynamicItemFromIndex(index
);
142 ++const_cast<CodeModelItem
*>(editableItem
->items())[a
].referenceCount
;
143 const_cast<CodeModelItem
*>(editableItem
->items())[a
].kind
= kind
;
144 return; //Already there
145 }else if(freePlace
== -1 && !items
[a
].id
.isValid()) {
146 freePlace
= (int)a
; //Remember an unused position where we can insert the item
147 ifDebug( kDebug() << "found free place at" << freePlace
; )
151 CodeModelItem newItem
;
152 newItem
.referenceCount
= 1;
156 if(freePlace
!= -1) {
157 //We can insert the item at a currently unused position
158 CodeModelRepositoryItem
* editableItem
= d
->m_repository
.dynamicItemFromIndex(index
);
159 const_cast<CodeModelItem
*>(editableItem
->items())[freePlace
] = newItem
;
160 ifDebug( kDebug() << "using freePlace" << freePlace
; )
164 item
.copyListsFrom(*oldItem
);
165 item
.itemsList().append(newItem
);
167 //Append a few additional items, so we don't need to re-create that often
168 item
.itemsList().append(CodeModelItem());
169 item
.itemsList().append(CodeModelItem());
170 item
.itemsList().append(CodeModelItem());
171 item
.itemsList().append(CodeModelItem());
173 ifDebug( kDebug() << "deleting list, and creating new with" << item
.itemsSize() << "items"; )
174 d
->m_repository
.deleteItem(index
);
176 //We're creating a new index
177 CodeModelItem newItem
;
178 newItem
.referenceCount
= 1;
181 item
.itemsList().append(newItem
);
183 Q_ASSERT(!d
->m_repository
.findIndex(request
));
185 //This inserts the changed item
186 uint newIndex
= d
->m_repository
.index(request
);
188 ifDebug( kDebug() << "new index" << newIndex
; )
190 Q_ASSERT(d
->m_repository
.findIndex(request
));
193 void CodeModel::updateItem(const IndexedString
& file
, const IndexedQualifiedIdentifier
& id
, CodeModelItem::Kind kind
)
195 ifDebug( kDebug() << file
.str() << id
.identifier().toString() << kind
; )
199 CodeModelRepositoryItem item
;
201 CodeModelRequestItem
request(item
);
203 uint index
= d
->m_repository
.findIndex(item
);
206 //Check whether the item is already in the mapped list, else copy the list into the new created item
207 const CodeModelRepositoryItem
* oldItem
= d
->m_repository
.itemFromIndex(index
);
208 uint itemsSize
= oldItem
->itemsSize();
209 const KDevelop::CodeModelItem
* items
= oldItem
->items();
211 for(uint a
= 0; a
< itemsSize
; ++a
) {
212 if(items
[a
].id
== id
) {
213 CodeModelRepositoryItem
* editableItem
= d
->m_repository
.dynamicItemFromIndex(index
);
214 const_cast<CodeModelItem
*>(editableItem
->items())[a
].kind
= kind
;
215 return; //Already there
220 Q_ASSERT(0); //The updated item as not in the symbol table!
223 void CodeModel::removeItem(const IndexedString
& file
, const IndexedQualifiedIdentifier
& id
)
224 //void CodeModel::removeDeclaration(const QualifiedIdentifier& id, const IndexedDeclaration& declaration)
228 ifDebug( kDebug() << "removeItem" << file
.str() << id
.identifier().toString(); )
229 CodeModelRepositoryItem item
;
231 CodeModelRequestItem
request(item
);
233 uint index
= d
->m_repository
.findIndex(item
);
237 uint freeItemCount
= 0;
239 CodeModelRepositoryItem
* oldItem
= d
->m_repository
.dynamicItemFromIndex(index
);
240 uint itemsSize
= oldItem
->itemsSize();
241 KDevelop::CodeModelItem
* items
= const_cast<CodeModelItem
*>(oldItem
->items());
243 for(uint a
= 0; a
< itemsSize
; ++a
) {
244 if(oldItem
->items()[a
].id
== id
) {
246 --items
[a
].referenceCount
;
247 ifDebug( kDebug() << "reduced reference-count for" << id
.identifier().toString() << "to" << oldItem
->items()[a
].referenceCount
; )
249 if(!items
[a
].referenceCount
) {
250 items
[a
].id
= IndexedQualifiedIdentifier();
251 ifDebug( kDebug() << "marking index" << a
<< "as free"; )
254 if(!items
[a
].id
.isValid()) {
258 if(freeItemCount
== itemsSize
) {
259 ifDebug( kDebug() << "no items left, deleting"; )
260 d
->m_repository
.deleteItem(index
);
261 }else if(freeItemCount
> 10) {
262 ifDebug( kDebug() << "resizing to make smaller"; )
264 for(uint a
= 0; a
< itemsSize
; ++a
)
265 if(items
[a
].id
.isValid())
266 item
.itemsList().append(items
[a
]);
268 d
->m_repository
.deleteItem(index
);
269 ifDebug( kDebug() << "creating new entry with" << item
.itemsSize() << "entries"; )
270 d
->m_repository
.index(request
);
275 void CodeModel::items(const IndexedString
& file
, uint
& count
, const CodeModelItem
*& items
) const
277 ifDebug( kDebug() << "items" << file
.str(); )
279 CodeModelRepositoryItem item
;
281 CodeModelRequestItem
request(item
);
283 uint index
= d
->m_repository
.findIndex(item
);
286 const CodeModelRepositoryItem
* repositoryItem
= d
->m_repository
.itemFromIndex(index
);
287 ifDebug( kDebug() << "found index" << index
<< repositoryItem
->itemsSize(); )
288 count
= repositoryItem
->itemsSize();
289 items
= repositoryItem
->items();
291 ifDebug( kDebug() << "found no index"; )
297 CodeModel
& CodeModel::self() {
298 static CodeModel ret
;