diff --git a/src/plugins/cpptools/builtinindexingsupport.cpp b/src/plugins/cpptools/builtinindexingsupport.cpp index 10d4029d28fb140cdf7e6481e97a1361997017ef..52877b73c8b228f0619a8a5793307913becb0b06 100644 --- a/src/plugins/cpptools/builtinindexingsupport.cpp +++ b/src/plugins/cpptools/builtinindexingsupport.cpp @@ -4,6 +4,7 @@ #include "cpppreprocessor.h" #include "searchsymbols.h" #include "cpptoolsconstants.h" +#include "cpptoolsplugin.h" #include "cppprojectfile.h" #include @@ -107,7 +108,7 @@ public: future.setProgressValue(0); int progress = 0; - SearchSymbols search; + SearchSymbols search(CppToolsPlugin::stringTable()); search.setSymbolsToSearchFor(m_parameters.types); CPlusPlus::Snapshot::const_iterator it = m_snapshot.begin(); diff --git a/src/plugins/cpptools/cppcurrentdocumentfilter.cpp b/src/plugins/cpptools/cppcurrentdocumentfilter.cpp index 03c160c8da8a6b31e85267c95464dffd7efe9c44..78308e173a185ebf3cd918601401b29c06d3c9c1 100644 --- a/src/plugins/cpptools/cppcurrentdocumentfilter.cpp +++ b/src/plugins/cpptools/cppcurrentdocumentfilter.cpp @@ -36,8 +36,10 @@ using namespace CppTools::Internal; using namespace CPlusPlus; -CppCurrentDocumentFilter::CppCurrentDocumentFilter(CppModelManager *manager) +CppCurrentDocumentFilter::CppCurrentDocumentFilter(CppModelManager *manager, + StringTable &stringTable) : m_modelManager(manager) + , search(stringTable) { setId("Methods in current Document"); setDisplayName(tr("C++ Symbols in Current Document")); @@ -57,7 +59,8 @@ CppCurrentDocumentFilter::CppCurrentDocumentFilter(CppModelManager *manager) this, SLOT(onEditorAboutToClose(Core::IEditor*))); } -QList CppCurrentDocumentFilter::matchesFor(QFutureInterface &future, const QString & origEntry) +QList CppCurrentDocumentFilter::matchesFor( + QFutureInterface &future, const QString & origEntry) { QString entry = trimWildcards(origEntry); QList goodEntries; diff --git a/src/plugins/cpptools/cppcurrentdocumentfilter.h b/src/plugins/cpptools/cppcurrentdocumentfilter.h index b181bc40bf43ca3838e4bd92cc49bdd7ff3f60a5..f3f7560ce192d26f7c0c2f329c3c45be8f9e5cac 100644 --- a/src/plugins/cpptools/cppcurrentdocumentfilter.h +++ b/src/plugins/cpptools/cppcurrentdocumentfilter.h @@ -45,7 +45,8 @@ class CppCurrentDocumentFilter : public Core::ILocatorFilter Q_OBJECT public: - explicit CppCurrentDocumentFilter(CppModelManager *manager); + explicit CppCurrentDocumentFilter(CppModelManager *manager, + StringTable &stringTable); ~CppCurrentDocumentFilter() {} QList matchesFor(QFutureInterface &future, const QString &entry); diff --git a/src/plugins/cpptools/cpplocatordata.cpp b/src/plugins/cpptools/cpplocatordata.cpp index a76b6802ca5a67278471eee038d96fabbcc384e9..27cebacd26b9d8a08b2d295262215b0bae2fd0d5 100644 --- a/src/plugins/cpptools/cpplocatordata.cpp +++ b/src/plugins/cpptools/cpplocatordata.cpp @@ -27,8 +27,8 @@ ** ****************************************************************************/ - #include "cpplocatordata.h" +#include "cpptoolsplugin.h" using namespace CppTools; using namespace CppTools::Internal; @@ -37,6 +37,8 @@ static const int MaxPendingDocuments = 10; CppLocatorData::CppLocatorData(CppModelManager *modelManager) : m_modelManager(modelManager) + , m_strings(CppToolsPlugin::stringTable()) + , m_search(m_strings) , m_pendingDocumentsMutex(QMutex::Recursive) { m_search.setSymbolsToSearchFor(SymbolSearcher::Enums @@ -104,8 +106,9 @@ void CppLocatorData::onAboutToRemoveFiles(const QStringList &files) m_allEnums.remove(file); m_allClasses.remove(file); m_allFunctions.remove(file); - removeFilePath(file); } + + m_strings.scheduleGC(); } void CppLocatorData::flushPendingDocument(bool force) diff --git a/src/plugins/cpptools/cpplocatordata.h b/src/plugins/cpptools/cpplocatordata.h index 941286144c3bcd70a58a136438223f2ee01a337f..b9a9ca1c18fc82b2479b4f70dad2f91c6e456a14 100644 --- a/src/plugins/cpptools/cpplocatordata.h +++ b/src/plugins/cpptools/cpplocatordata.h @@ -38,6 +38,7 @@ #include "cppmodelmanager.h" #include "searchsymbols.h" +#include "stringtable.h" namespace CppTools { namespace Internal { @@ -62,15 +63,12 @@ private: QList > &items) const; QString findOrInsertFilePath(const QString &path) - { return *m_filePaths.insert(path); } - - void removeFilePath(const QString &path) - { m_filePaths.remove(path); } + { return m_strings.insert(path); } private: CppModelManager *m_modelManager; - QSet m_filePaths; // Used to avoid QString duplication + StringTable &m_strings; // Used to avoid QString duplication SearchSymbols m_search; QHash > m_allEnums; diff --git a/src/plugins/cpptools/cpptools.pro b/src/plugins/cpptools/cpptools.pro index fed219f894f3dc0d43872c9f6edf5867717279a0..7bb174c261e424ec607ebfec8866f01d387bad0c 100644 --- a/src/plugins/cpptools/cpptools.pro +++ b/src/plugins/cpptools/cpptools.pro @@ -52,6 +52,7 @@ HEADERS += \ includeutils.h \ insertionpointlocator.h \ searchsymbols.h \ + stringtable.h \ symbolfinder.h \ symbolsfindfilter.h \ typehierarchybuilder.h @@ -104,6 +105,7 @@ SOURCES += \ includeutils.cpp \ insertionpointlocator.cpp \ searchsymbols.cpp \ + stringtable.cpp \ symbolfinder.cpp \ symbolsfindfilter.cpp \ typehierarchybuilder.cpp diff --git a/src/plugins/cpptools/cpptools.qbs b/src/plugins/cpptools/cpptools.qbs index 979614f2bc4c918ba64a8b9b84104ab54ef5c052..14927d03e6c93dbce31e8b6d819e3393a6b707b3 100644 --- a/src/plugins/cpptools/cpptools.qbs +++ b/src/plugins/cpptools/cpptools.qbs @@ -72,6 +72,7 @@ QtcPlugin { "includeutils.cpp", "includeutils.h", "insertionpointlocator.cpp", "insertionpointlocator.h", "searchsymbols.cpp", "searchsymbols.h", + "stringtable.cpp", "stringtable.h", "symbolfinder.cpp", "symbolfinder.h", "symbolsfindfilter.cpp", "symbolsfindfilter.h", "typehierarchybuilder.cpp", "typehierarchybuilder.h", diff --git a/src/plugins/cpptools/cpptoolsplugin.cpp b/src/plugins/cpptools/cpptoolsplugin.cpp index e46947124578acab93bcd66cf463a98d2f820906..d9fee99923698c09c86319b2e1d27aee18bf67d9 100644 --- a/src/plugins/cpptools/cpptoolsplugin.cpp +++ b/src/plugins/cpptools/cpptoolsplugin.cpp @@ -136,7 +136,7 @@ bool CppToolsPlugin::initialize(const QStringList &arguments, QString *error) addAutoReleasedObject(new CppLocatorFilter(locatorData)); addAutoReleasedObject(new CppClassesFilter(locatorData)); addAutoReleasedObject(new CppFunctionsFilter(locatorData)); - addAutoReleasedObject(new CppCurrentDocumentFilter(modelManager)); + addAutoReleasedObject(new CppCurrentDocumentFilter(modelManager, m_stringTable)); addAutoReleasedObject(new CppFileSettingsPage(m_fileSettings)); addAutoReleasedObject(new CppCodeModelSettingsPage(m_codeModelSettings)); addAutoReleasedObject(new SymbolsFindFilter(modelManager)); @@ -190,6 +190,11 @@ QSharedPointer CppToolsPlugin::codeModelSettings() const return m_codeModelSettings; } +StringTable &CppToolsPlugin::stringTable() +{ + return instance()->m_stringTable; +} + void CppToolsPlugin::switchHeaderSource() { QString otherFile = correspondingHeaderOrSource( diff --git a/src/plugins/cpptools/cpptoolsplugin.h b/src/plugins/cpptools/cpptoolsplugin.h index ce55cf668eccdfd25aef0c79d0f4f6bbb6d49374..00a8a05567c66b7c498e42e2142977702052c185 100644 --- a/src/plugins/cpptools/cpptoolsplugin.h +++ b/src/plugins/cpptools/cpptoolsplugin.h @@ -31,6 +31,7 @@ #define CPPTOOLS_H #include "cpptools_global.h" +#include "stringtable.h" #include @@ -73,6 +74,8 @@ public: QSharedPointer codeModelSettings() const; + static StringTable &stringTable(); + public slots: void switchHeaderSource(); void switchHeaderSourceInNextSplit(); @@ -163,6 +166,7 @@ private: QSharedPointer m_fileSettings; QSharedPointer m_codeModelSettings; CppToolsSettings *m_settings; + StringTable m_stringTable; }; } // namespace Internal diff --git a/src/plugins/cpptools/searchsymbols.cpp b/src/plugins/cpptools/searchsymbols.cpp index c7b2320264bb3c5dfeda965a35a1623b082450ce..a166c56f9649e40d4cf07d8fc068c677bc275223 100644 --- a/src/plugins/cpptools/searchsymbols.cpp +++ b/src/plugins/cpptools/searchsymbols.cpp @@ -42,8 +42,9 @@ SearchSymbols::SymbolTypes SearchSymbols::AllTypes = | SymbolSearcher::Enums | SymbolSearcher::Declarations; -SearchSymbols::SearchSymbols() : - symbolsToSearchFor(SymbolSearcher::Classes | SymbolSearcher::Functions | SymbolSearcher::Enums) +SearchSymbols::SearchSymbols(Internal::StringTable &stringTable) + : strings(stringTable) + , symbolsToSearchFor(SymbolSearcher::Classes | SymbolSearcher::Functions | SymbolSearcher::Enums) { } @@ -62,7 +63,7 @@ QList SearchSymbols::operator()(Document::Ptr doc, int sizeHint, } (void) switchScope(previousScope); QList result = items; - strings.clear(); + strings.scheduleGC(); items.clear(); m_paths.clear(); return result; @@ -291,7 +292,7 @@ void SearchSymbols::appendItem(const QString &symbolName, const QString &symbolT findOrInsert(symbolType), findOrInsert(symbolScope), itemType, - path, + findOrInsert(path), symbol->line(), symbol->column() - 1, // 1-based vs 0-based column icon)); diff --git a/src/plugins/cpptools/searchsymbols.h b/src/plugins/cpptools/searchsymbols.h index 1b0a8811255850e8fe4dd79de061ba757e50cba4..dee20aa3c7dabe151d22677f17db9011acd3adf9 100644 --- a/src/plugins/cpptools/searchsymbols.h +++ b/src/plugins/cpptools/searchsymbols.h @@ -32,6 +32,7 @@ #include "cpptools_global.h" #include "cppindexingsupport.h" +#include "stringtable.h" #include #include @@ -140,7 +141,7 @@ public: static SymbolTypes AllTypes; - SearchSymbols(); + SearchSymbols(Internal::StringTable &stringTable); void setSymbolsToSearchFor(const SymbolTypes &types); @@ -193,9 +194,9 @@ protected: private: QString findOrInsert(const QString &s) - { return *strings.insert(s); } + { return strings.insert(s); } - QSet strings; // Used to avoid QString duplication + Internal::StringTable &strings; // Used to avoid QString duplication QString _scope; CPlusPlus::Overview overview; diff --git a/src/plugins/cpptools/stringtable.cpp b/src/plugins/cpptools/stringtable.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6d284536eeb85e634b69bc45c34636c6f2de5b76 --- /dev/null +++ b/src/plugins/cpptools/stringtable.cpp @@ -0,0 +1,116 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "stringtable.h" + +#include +#include +#include + +using namespace CppTools::Internal; + +enum { + GCTimeOut = 10 * 1000 // 10 seconds +}; + +StringTable::StringTable() + : m_gcRunner(*this) + , m_stopGCRequested(false) +{ + m_strings.reserve(1000); + + m_gcRunner.setAutoDelete(false); + + m_gcCountDown.setSingleShot(true); + m_gcCountDown.setInterval(GCTimeOut); + connect(&m_gcCountDown, SIGNAL(timeout()), + this, SLOT(startGC())); +} + +QString StringTable::insert(const QString &string) +{ + if (string.isEmpty()) + return string; + + + m_stopGCRequested.fetchAndStoreAcquire(true); + + QMutexLocker locker(&m_lock); + QString result = *m_strings.insert(string); + m_stopGCRequested.storeRelease(false); + return result; +} + +void StringTable::scheduleGC() +{ + QMutexLocker locker(&m_lock); + + m_gcCountDown.start(); +} + +void StringTable::startGC() +{ + QThreadPool::globalInstance()->start(&m_gcRunner); +} + +enum { + DebugStringTable = 0 +}; + +void StringTable::GC() +{ + QMutexLocker locker(&m_lock); + + int initialSize = 0; + int startTime = 0; + if (DebugStringTable) { + initialSize = m_strings.size(); + startTime = QTime::currentTime().msecsSinceStartOfDay(); + } + + // Collect all QStrings which have refcount 1. (One reference in m_strings and nowhere else.) + for (QSet::iterator i = m_strings.begin(); i != m_strings.end();) { + if (m_stopGCRequested.testAndSetRelease(true, false)) + return; + + const int refCount = const_cast(*i).data_ptr()->ref.atomic.load(); + if (refCount == 1) + i = m_strings.erase(i); + else + ++i; + } + + if (DebugStringTable) { + const int endTime = QTime::currentTime().msecsSinceStartOfDay(); + const int currentSize = m_strings.size(); + qDebug() << "StringTable::GC removed" << initialSize - currentSize + << "strings in" << endTime - startTime + << "ms, size is now" << currentSize; + } +} diff --git a/src/plugins/cpptools/stringtable.h b/src/plugins/cpptools/stringtable.h new file mode 100644 index 0000000000000000000000000000000000000000..31852f635f9fea04e3f77e0797e3b458a2a0aa48 --- /dev/null +++ b/src/plugins/cpptools/stringtable.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef STRINGTABLE_H +#define STRINGTABLE_H + +#include +#include +#include +#include +#include +#include + +namespace CppTools { +namespace Internal { + +class StringTable: public QObject +{ + Q_OBJECT + +public: + StringTable(); + + QString insert(const QString &string); + void scheduleGC(); + +private slots: + void startGC(); + +private: + void GC(); + class GCRunner: public QRunnable { + StringTable &m_stringTable; + + public: + GCRunner(StringTable &stringTable): m_stringTable(stringTable) {} + virtual void run() { m_stringTable.GC(); } + } m_gcRunner; + friend class GCRunner; + +private: + mutable QMutex m_lock; + QAtomicInt m_stopGCRequested; + QSet m_strings; + QTimer m_gcCountDown; +}; + +} // Internal namespace +} // CppTools namespace + +#endif // STRINGTABLE_H