Autotest: Introduce ItemDataCache

Change-Id: Icbd703a8ddd3c5dea4a90d2c32c1866764bc0267
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
David Schulz
2020-06-18 12:32:48 +02:00
parent 286d1832e6
commit dfd7bdd22a
4 changed files with 57 additions and 49 deletions

View File

@@ -111,7 +111,6 @@ TestNavigationWidget::TestNavigationWidget(QWidget *parent) :
connect(sm, &ProjectExplorer::SessionManager::startupProjectChanged,
this, [this](ProjectExplorer::Project * /*project*/) {
m_expandedStateCache.clear();
m_itemUseCache.clear();
});
connect(m_model, &TestTreeModel::testTreeModelChanged,
this, &TestNavigationWidget::reapplyCachedExpandedState);
@@ -237,22 +236,12 @@ QList<QToolButton *> TestNavigationWidget::createToolButtons()
void TestNavigationWidget::updateExpandedStateCache()
{
// raise generation for cached items and drop anything reaching 10th generation
const QList<QString> cachedNames = m_itemUseCache.keys();
for (const QString &cachedName : cachedNames) {
auto it = m_itemUseCache.find(cachedName);
if (it.value()++ >= 10) {
m_itemUseCache.erase(it);
m_expandedStateCache.remove(cachedName);
}
}
m_expandedStateCache.evolve();
for (Utils::TreeItem *rootNode : *m_model->rootItem()) {
rootNode->forAllChildren([this](Utils::TreeItem *child) {
auto childItem = static_cast<TestTreeItem *>(child);
const QString cacheName = childItem->cacheName();
m_expandedStateCache.insert(cacheName, m_view->isExpanded(childItem->index()));
m_itemUseCache[cacheName] = 0; // explicitly mark as 0-generation
m_expandedStateCache.insert(static_cast<TestTreeItem *>(child),
m_view->isExpanded(child->index()));
});
}
}
@@ -328,16 +317,15 @@ void TestNavigationWidget::onRunThisTestTriggered(TestRunMode runMode)
void TestNavigationWidget::reapplyCachedExpandedState()
{
for (Utils::TreeItem *rootNode : *m_model->rootItem()) {
rootNode->forAllChildren([this](Utils::TreeItem *child) {
auto childItem = static_cast<TestTreeItem *>(child);
const QString cacheName = childItem->cacheName();
const auto it = m_expandedStateCache.find(cacheName);
if (it == m_expandedStateCache.end())
return;
QModelIndex index = child->index();
if (m_view->isExpanded(index) != it.value())
m_view->setExpanded(index, it.value());
using namespace Utils;
for (TreeItem *rootNode : *m_model->rootItem()) {
rootNode->forAllChildren([this](TreeItem *child) {
optional<bool> cached = m_expandedStateCache.get(static_cast<TestTreeItem *>(child));
if (cached.has_value()) {
QModelIndex index = child->index();
if (m_view->isExpanded(index) != cached.value())
m_view->setExpanded(index, cached.value());
}
});
}
}

View File

@@ -27,6 +27,8 @@
#include "testrunner.h"
#include "testtreemodel.h"
#include <coreplugin/inavigationwidgetfactory.h>
#include <utils/navigationtreeview.h>
@@ -47,12 +49,8 @@ class ProgressIndicator;
}
namespace Autotest {
class TestTreeModel;
namespace Internal {
class TestTreeSortFilterModel;
class TestTreeView;
class TestNavigationWidget : public QWidget
@@ -86,8 +84,7 @@ private:
Utils::ProgressIndicator *m_progressIndicator;
QTimer *m_progressTimer;
QFrame *m_missingFrameworksWidget;
QHash<QString, bool> m_expandedStateCache;
QHash<QString, int> m_itemUseCache;
ItemDataCache<bool> m_expandedStateCache;
};
class TestNavigationWidgetFactory : public Core::INavigationWidgetFactory

View File

@@ -92,7 +92,6 @@ void TestTreeModel::setupParsingConnections()
synchronizeTestFrameworks(); // we might have project settings
m_parser->onStartupProjectChanged(project);
m_checkStateCache.clear(); // TODO persist to project settings?
m_itemUseCache.clear();
});
CppTools::CppModelManager *cppMM = CppTools::CppModelManager::instance();
@@ -295,22 +294,12 @@ void TestTreeModel::rebuild(const QList<Utils::Id> &frameworkIds)
void TestTreeModel::updateCheckStateCache()
{
// raise generation for cached items and drop anything reaching 10th generation
const QList<QString> cachedNames = m_itemUseCache.keys();
for (const QString &cachedName : cachedNames) {
auto it = m_itemUseCache.find(cachedName);
if (it.value()++ >= 10) {
m_itemUseCache.erase(it);
m_checkStateCache.remove(cachedName);
}
}
m_checkStateCache.evolve();
for (Utils::TreeItem *rootNode : *rootItem()) {
rootNode->forAllChildren([this](Utils::TreeItem *child) {
auto childItem = static_cast<TestTreeItem *>(child);
const QString cacheName = childItem->cacheName();
m_checkStateCache.insert(cacheName, childItem->checked());
m_itemUseCache[cacheName] = 0; // explicitly mark as 0-generation
m_checkStateCache.insert(childItem, childItem->checked());
});
}
}
@@ -436,8 +425,8 @@ void TestTreeModel::insertItemInParent(TestTreeItem *item, TestTreeItem *root, b
delete item;
} else {
// restore former check state if available
auto cached = m_checkStateCache.find(item->cacheName());
if (cached != m_checkStateCache.end())
Utils::optional<Qt::CheckState> cached = m_checkStateCache.get(item);
if (cached.has_value())
item->setData(0, cached.value(), Qt::CheckStateRole);
else
applyParentCheckState(parentNode, item);
@@ -526,8 +515,8 @@ void TestTreeModel::handleParseResult(const TestParseResult *result, TestTreeIte
// restore former check state if available
newItem->forAllChildren([this](Utils::TreeItem *child) {
auto childItem = static_cast<TestTreeItem *>(child);
auto cached = m_checkStateCache.find(childItem->cacheName());
if (cached != m_checkStateCache.end())
Utils::optional<Qt::CheckState> cached = m_checkStateCache.get(childItem);
if (cached.has_value())
childItem->setData(0, cached.value(), Qt::CheckStateRole);
});
// it might be necessary to "split" created item

View File

@@ -30,6 +30,7 @@
#include "testconfiguration.h"
#include "testtreeitem.h"
#include <utils/algorithm.h>
#include <utils/treemodel.h>
#include <QSortFilterProxyModel>
@@ -38,6 +39,40 @@ namespace Autotest {
namespace Internal {
class AutotestPluginPrivate;
class TestCodeParser;
template<class T>
class ItemDataCache
{
public:
void insert(TestTreeItem *item, const T &value) { m_cache[item->cacheName()] = {0, value}; }
void evolve()
{
auto it = m_cache.begin(), end = m_cache.end();
while (it != end)
it = it->generation++ >= maxGen ? m_cache.erase(it) : ++it;
}
Utils::optional<T> get(TestTreeItem *item)
{
auto entry = m_cache.find(item->cacheName());
if (entry == m_cache.end())
return Utils::nullopt;
entry->generation = 0;
return Utils::make_optional(entry->value);
};
void clear() { m_cache.clear(); }
private:
static constexpr int maxGen = 10;
struct Entry
{
int generation = 0;
T value;
};
QHash<QString, Entry> m_cache;
};
} // namespace Internal
class TestParseResult;
@@ -104,8 +139,7 @@ private:
QList<TestTreeItem *> testItemsByName(TestTreeItem *root, const QString &testName);
Internal::TestCodeParser *m_parser = nullptr;
QHash<QString, Qt::CheckState> m_checkStateCache;
QHash<QString, int> m_itemUseCache;
Internal::ItemDataCache<Qt::CheckState> m_checkStateCache;
};
namespace Internal {