language/duchain
appendedlist.h
00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #ifndef APPENDEDLIST_H
00020 #define APPENDEDLIST_H
00021
00022 #include <QtCore/QMutex>
00023 #include <QtCore/QVector>
00024 #include <QtCore/QStack>
00025 #include <kglobal.h>
00026 #include <kdebug.h>
00027 #include <util/kdevvarlengtharray.h>
00028 #include <iostream>
00029 #include <time.h>
00030
00031 namespace KDevelop {
00032 class AbstractItemRepository;
00053 enum {
00054 DynamicAppendedListMask = 1 << 31
00055 };
00056 enum {
00057 DynamicAppendedListRevertMask = ~DynamicAppendedListMask
00058 };
00066 template<class T, bool threadSafe = true>
00067 class TemporaryDataManager {
00068 public:
00069 TemporaryDataManager(QString id = QString()) : m_itemsUsed(0), m_itemsSize(0), m_items(0), m_id(id) {
00070 uint first = alloc();
00071 Q_ASSERT(first == (uint)DynamicAppendedListMask);
00072 }
00073 ~TemporaryDataManager() {
00074 free(DynamicAppendedListMask);
00075 uint cnt = usedItemCount();
00076 if(cnt)
00077 std::cout << m_id.toLocal8Bit().data() << " There were items left on destruction: " << usedItemCount() << "\n";
00078
00079 for(uint a = 0; a < m_itemsUsed; ++a)
00080 delete m_items[a];
00081 }
00082
00083 inline T& getItem(uint index) {
00084
00085
00086 Q_ASSERT(index & DynamicAppendedListMask);
00087
00088 return *m_items[index & KDevelop::DynamicAppendedListRevertMask];
00089 }
00090
00093 uint alloc() {
00094
00095 if(threadSafe)
00096 m_mutex.lock();
00097
00098 uint ret;
00099 if(!m_freeIndicesWithData.isEmpty()) {
00100 ret = m_freeIndicesWithData.pop();
00101 }else if(!m_freeIndices.isEmpty()) {
00102 ret = m_freeIndices.pop();
00103 Q_ASSERT(!m_items[ret]);
00104 m_items[ret] = new T;
00105 }else{
00106
00107 if(m_itemsUsed >= m_itemsSize) {
00108
00109 uint newItemsSize = m_itemsSize + 20 + (m_itemsSize/3);
00110 T** newItems = new T*[newItemsSize];
00111 memcpy(newItems, m_items, sizeof(T*) * m_itemsSize);
00112
00113 T** oldItems = m_items;
00114 m_items = newItems;
00115 m_itemsSize = newItemsSize;
00116
00117
00118
00119 m_deleteLater.append(qMakePair(time(0), oldItems));
00120
00121
00122
00123 if(!m_deleteLater.isEmpty()) {
00124 while(!m_deleteLater.isEmpty()) {
00125
00126 if(time(0) - m_deleteLater.first().first > 5) {
00127 delete[] m_deleteLater.first().second;
00128 m_deleteLater.removeFirst();
00129 }else{
00130 break;
00131 }
00132 }
00133 }
00134 }
00135
00136 ret = m_itemsUsed;
00137 m_items[m_itemsUsed] = new T;
00138 ++m_itemsUsed;
00139 Q_ASSERT(m_itemsUsed <= m_itemsSize);
00140 }
00141
00142 if(threadSafe)
00143 m_mutex.unlock();
00144
00145 Q_ASSERT(!(ret & DynamicAppendedListMask));
00146
00147 return ret | DynamicAppendedListMask;
00148 }
00149
00150 void free(uint index) {
00151 Q_ASSERT(index & DynamicAppendedListMask);
00152 index &= KDevelop::DynamicAppendedListRevertMask;
00153
00154 if(threadSafe)
00155 m_mutex.lock();
00156
00157 freeItem(m_items[index]);
00158
00159 m_freeIndicesWithData.push(index);
00160
00161
00162 if(m_freeIndicesWithData.size() > 200) {
00163 for(int a = 0; a < 100; ++a) {
00164 uint deleteIndexData = m_freeIndicesWithData.pop();
00165 delete m_items[deleteIndexData];
00166 m_items[deleteIndexData] = 0;
00167 m_freeIndices.push(deleteIndexData);
00168 }
00169 }
00170
00171 if(threadSafe)
00172 m_mutex.unlock();
00173 }
00174
00175 uint usedItemCount() const {
00176 uint ret = 0;
00177 for(uint a = 0; a < m_itemsUsed; ++a)
00178 if(m_items[a])
00179 ++ret;
00180 return ret - m_freeIndicesWithData.size();
00181 }
00182
00183 private:
00184
00185 void freeItem(T* item) {
00186 item->clear();
00187 }
00188
00189 uint m_itemsUsed, m_itemsSize;
00190 T** m_items;
00191 QStack<uint> m_freeIndicesWithData;
00192 QStack<uint> m_freeIndices;
00193 QMutex m_mutex;
00194 QString m_id;
00195 QList<QPair<time_t, T**> > m_deleteLater;
00196 };
00197
00199
00200 #define FOREACH_FUNCTION(item, container) for(uint a = 0, mustDo = 1, containerSize = container ## Size(); a < containerSize; ++a) if((mustDo == 0 || mustDo == 1) && (mustDo = 2)) for(item(container()[a]); mustDo; mustDo = 0)
00201
00202
00203
00204 #define DEFINE_LIST_MEMBER_HASH(container, member, type) \
00205 typedef TemporaryDataManager<KDevVarLengthArray<type, 10> > temporaryHash ## container ## member ## Type; \
00206 K_GLOBAL_STATIC_WITH_ARGS(temporaryHash ## container ## member ## Type, temporaryHash ## container ## member ## Static, ( #container "::" #member )) \
00207 temporaryHash ## container ## member ## Type& temporaryHash ## container ## member() { \
00208 return *temporaryHash ## container ## member ## Static; \
00209 }
00210
00211 #define DECLARE_LIST_MEMBER_HASH(container, member, type) KDevelop::TemporaryDataManager<KDevVarLengthArray<type, 10> >& temporaryHash ## container ## member();
00212
00223 #define APPENDED_LISTS_STUB(container) \
00224 bool m_dynamic : 1; \
00225 unsigned int offsetBehindLastList() const { return 0; } \
00226 size_t dynamicSize() const { return classSize(); } \
00227 template<class T> bool listsEqual(const T& ) const { return true; } \
00228 template<class T> void copyAllFrom(const T& ) const { } \
00229 void initializeAppendedLists(bool dynamic = appendedListDynamicDefault()) { m_dynamic = dynamic; } \
00230 void freeAppendedLists() { } \
00231 bool appendedListsDynamic() const { return m_dynamic; }
00232
00233
00235 #define START_APPENDED_LISTS(container) \
00236 unsigned int offsetBehindBase() const { return 0; } \
00237 void freeDynamicData() { freeAppendedLists(); }
00238
00242 #define START_APPENDED_LISTS_BASE(container, base) \
00243 unsigned int offsetBehindBase() const { return base :: offsetBehindLastList(); } \
00244 void freeDynamicData() { freeAppendedLists(); base::freeDynamicData(); }
00245
00246
00247 #define APPENDED_LIST_COMMON(container, type, name) \
00248 uint name ## Data; \
00249 unsigned int name ## Size() const { if((name ## Data & KDevelop::DynamicAppendedListRevertMask) == 0) return 0; if(!appendedListsDynamic()) return name ## Data; else return temporaryHash ## container ## name().getItem(name ## Data).size(); } \
00250 KDevVarLengthArray<type, 10>& name ## List() { name ## NeedDynamicList(); return temporaryHash ## container ## name().getItem(name ## Data); }\
00251 template<class T> bool name ## Equals(const T& rhs) const { unsigned int size = name ## Size(); if(size != rhs.name ## Size()) return false; for(uint a = 0; a < size; ++a) {if(!(name()[a] == rhs.name()[a])) return false;} return true; } \
00252 template<class T> void name ## CopyFrom( const T& rhs ) { \
00253 if(rhs.name ## Size() == 0 && (name ## Data & KDevelop::DynamicAppendedListRevertMask) == 0) return; \
00254 if(appendedListsDynamic()) { \
00255 name ## NeedDynamicList(); \
00256 KDevVarLengthArray<type, 10>& item( temporaryHash ## container ## name().getItem(name ## Data) ); \
00257 item.clear(); \
00258 const type* otherCurr = rhs.name(); \
00259 const type* otherEnd = otherCurr + rhs.name ## Size(); \
00260 for(; otherCurr < otherEnd; ++otherCurr) \
00261 item.append(*otherCurr); \
00262 }else{ \
00263 Q_ASSERT(name ## Data == 0); \
00264 name ## Data = rhs.name ## Size(); \
00265 type* curr = const_cast<type*>(name()); type* end = curr + name ## Size(); \
00266 const type* otherCurr = rhs.name(); \
00267 for(; curr < end; ++curr, ++otherCurr) \
00268 new (curr) type(*otherCurr); \
00269 }\
00270 } \
00271 void name ## NeedDynamicList() { Q_ASSERT(appendedListsDynamic()); if((name ## Data & KDevelop::DynamicAppendedListRevertMask) == 0) { name ## Data = temporaryHash ## container ## name().alloc(); Q_ASSERT(temporaryHash ## container ## name().getItem(name ## Data).isEmpty()); } } \
00272 void name ## Initialize(bool dynamic) { name ## Data = (dynamic ? KDevelop::DynamicAppendedListMask : 0); } \
00273 void name ## Free() { if(appendedListsDynamic()) { if(name ## Data & KDevelop::DynamicAppendedListRevertMask) temporaryHash ## container ## name().free(name ## Data); } else { type* curr = const_cast<type*>(name()); type* end = curr + name ## Size(); for(; curr < end; ++curr) curr->~type(); } } \
00274
00275
00277
00278 #define APPENDED_LIST_FIRST(container, type, name) APPENDED_LIST_COMMON(container, type, name) \
00279 const type* name() const { if((name ## Data & KDevelop::DynamicAppendedListRevertMask) == 0) return 0; if(!appendedListsDynamic()) return (type*)(((char*)this) + classSize() + offsetBehindBase()); else return temporaryHash ## container ## name().getItem(name ## Data).data(); } \
00280 unsigned int name ## OffsetBehind() const { return name ## Size() * sizeof(type) + offsetBehindBase(); } \
00281 template<class T> bool name ## ListChainEquals( const T& rhs ) const { return name ## Equals(rhs); } \
00282 template<class T> void name ## CopyAllFrom( const T& rhs ) { name ## CopyFrom(rhs); } \
00283 void name ## InitializeChain(bool dynamic) { name ## Initialize(dynamic); } \
00284 void name ## FreeChain() { name ## Free(); }
00285
00286 #define APPENDED_LIST(container, type, name, predecessor) APPENDED_LIST_COMMON(container, type, name) \
00287 const type* name() const {if((name ## Data & KDevelop::DynamicAppendedListRevertMask) == 0) return 0; if(!appendedListsDynamic()) return (type*)(((char*)this) + classSize() + predecessor ## OffsetBehind()); else return temporaryHash ## container ## name().getItem(name ## Data).data(); } \
00288 unsigned int name ## OffsetBehind() const { return name ## Size() * sizeof(type) + predecessor ## OffsetBehind(); } \
00289 template<class T> bool name ## ListChainEquals( const T& rhs ) const { return name ## Equals(rhs) && predecessor ## ListChainEquals(rhs); } \
00290 template<class T> void name ## CopyAllFrom( const T& rhs ) { predecessor ## CopyAllFrom(rhs); name ## CopyFrom(rhs); } \
00291 void name ## InitializeChain(bool dynamic) { name ## Initialize(dynamic); predecessor ## InitializeChain(dynamic); } \
00292 void name ## FreeChain() { name ## Free(); predecessor ## FreeChain(); }
00293
00294 #define END_APPENDED_LISTS(container, predecessor) \
00295 unsigned int completeSize() const { return classSize() + predecessor ## OffsetBehind(); } \
00296 \
00297 template<class T> bool listsEqual(const T& rhs) const { return predecessor ## ListChainEquals(rhs); } \
00298 \
00299 template<class T> void copyListsFrom(const T& rhs) { return predecessor ## CopyAllFrom(rhs); } \
00300 void initializeAppendedLists(bool dynamic = appendedListDynamicDefault()) { predecessor ## Data = (dynamic ? KDevelop::DynamicAppendedListMask : 0); predecessor ## InitializeChain(dynamic); } \
00301 void freeAppendedLists() { predecessor ## FreeChain(); } \
00302 bool appendedListsDynamic() const { return predecessor ## Data & KDevelop::DynamicAppendedListMask; } \
00303 unsigned int offsetBehindLastList() const { return predecessor ## OffsetBehind(); } \
00304 size_t dynamicSize() const { return offsetBehindLastList() + classSize(); }
00305
00318 template<class Type, uint averageAppendedBytes = 8>
00319 class AppendedListItemRequest {
00320 public:
00321 AppendedListItemRequest(const Type& item) : m_item(item) {
00322 }
00323
00324 enum {
00325 AverageSize = sizeof(Type) + averageAppendedBytes
00326 };
00327
00328 unsigned int hash() const {
00329 return m_item.hash();
00330 }
00331
00332 size_t itemSize() const {
00333 return m_item.dynamicSize();
00334 }
00335
00336 void createItem(Type* item) const {
00337 new (item) Type(m_item, false);
00338 }
00339
00340 static void destroy(Type* item, KDevelop::AbstractItemRepository&) {
00341 item->~Type();
00342 }
00343
00344 static bool persistent(const Type* item) {
00345 return item->persistent();
00346 }
00347
00348 bool equals(const Type* item) const {
00349 return m_item == *item;
00350 }
00351
00352 const Type& m_item;
00353 };
00354 }
00355
00358 inline bool appendedListDynamicDefault() {
00359 return true;
00360 }
00361
00362 #endif