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

language/duchain

appendedlist.h

00001 /*
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 #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();  //Allocate the zero item, just to reserve that index
00071       Q_ASSERT(first == (uint)DynamicAppendedListMask);
00072     }
00073     ~TemporaryDataManager() {
00074       free(DynamicAppendedListMask); //Free the zero index, so we don't get wrong warnings
00075       uint cnt = usedItemCount();
00076       if(cnt) //Don't use kDebug, because that may not work during destruction
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       //For performance reasons this function does not lock the mutex, it's called too often and must be
00085       //extremely fast. There is special measures in alloc() to make this safe.
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           //We need to re-allocate
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           //The only function that does not lock the mutex is getItem(..), because that function must be very efficient.
00117           //Since it's only a few instructions from the moment m_items is read to the moment it's used,
00118           //deleting the old data after a few seconds should be safe.
00119           m_deleteLater.append(qMakePair(time(0), oldItems));
00120 
00121           //We do this in this place so it isn't called too often. The result is that we will always have some additional data around.
00122           //However the index itself should anyway not consume too much data.
00123           if(!m_deleteLater.isEmpty()) {
00124             while(!m_deleteLater.isEmpty()) {
00125               //We delete after 5 seconds
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       //Hold the amount of free indices with data between 100 and 200
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     //To save some memory, clear the lists
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 //This might be a little slow
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 //More efficient version that does not repeatedly call functions on the container, but the syntax is a bit less nice
00202 // #define FOREACH_FUNCTION_EFFICIENT(itemType, itemName, container) for(itemType* start = container(), end = start + container ## Size(), fake = start; start != end; ++start) for( itemType itemName(*start); fake != end; fake = end)
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& /*rhs*/) const { return true; } \
00228 template<class T> void copyAllFrom(const T& /*rhs*/) 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); /* It is dangerous to overwrite the contents of non-dynamic lists(Most probably a mistake) */ \
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); /* Call the copy constructors */ \
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(); /*call destructors*/ } }  \
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) /* Returns the size of the object containing the appended lists, including them */ \
00295                                       unsigned int completeSize() const { return classSize() + predecessor ## OffsetBehind(); } \
00296                                      /* Compares all local appended lists(not from base classes) and returns true if they are equal */                \
00297                                       template<class T> bool listsEqual(const T& rhs) const { return predecessor ## ListChainEquals(rhs); } \
00298                                      /* Copies all the local appended lists(not from base classes) from the given item.*/   \
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

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