Browse Source

Prevent possible c++11 range-loop container detach

Explicit or implicit calls to begin() and end() cause a non-const
container to detach from shared data, ie. to perform a deep-copy to gain
a unique copy of the data.
That can be a expensive although unneeded operation.

In order to assist the developer a copyAsConst function is added.
copyAsConst returns a const copy of the object.

For lvalues just use qAsConst. It's only available on Qt 5.7.0. But we
added also for earlier versions. The developer can always use qAsConst.

Intended uses:

    QString s = ...;
    for (const auto &ch : qAsConst(s))
          process(ch);

    for (const auto &ch : copyAsConst(funcReturningQString()))
        process(ch);
adaptive-webui-19844
Luís Pereira 7 years ago
parent
commit
1a913c502b
  1. 18
      src/base/global.h
  2. 8
      src/base/rss/rss_autodownloader.cpp
  3. 5
      src/base/rss/rss_folder.cpp
  4. 3
      src/base/utils/fs.cpp
  5. 5
      src/gui/ipsubnetwhitelistoptionsdialog.cpp
  6. 5
      src/gui/properties/speedplotview.cpp
  7. 3
      src/webui/api/appcontroller.cpp

18
src/base/global.h

@ -26,5 +26,23 @@ @@ -26,5 +26,23 @@
* exception statement from your version.
*/
#pragma once
#include <type_traits>
#include <QtGlobal>
const char C_TORRENT_FILE_EXTENSION[] = ".torrent";
#if QT_VERSION < QT_VERSION_CHECK(5, 7, 0)
template <typename T>
constexpr typename std::add_const<T>::type &qAsConst(T &t) noexcept { return t; }
// prevent rvalue arguments:
template <typename T>
void qAsConst(const T &&) = delete;
#endif
// returns a const object copy
template <typename T>
constexpr typename std::add_const<T>::type copyAsConst(T &&t) noexcept { return std::move(t); }

8
src/base/rss/rss_autodownloader.cpp

@ -43,6 +43,7 @@ @@ -43,6 +43,7 @@
#include "../bittorrent/magneturi.h"
#include "../bittorrent/session.h"
#include "../asyncfilestorage.h"
#include "../global.h"
#include "../logger.h"
#include "../profile.h"
#include "../settingsstorage.h"
@ -239,7 +240,7 @@ void AutoDownloader::importRules(const QByteArray &data, AutoDownloader::RulesFi @@ -239,7 +240,7 @@ void AutoDownloader::importRules(const QByteArray &data, AutoDownloader::RulesFi
QByteArray AutoDownloader::exportRulesToJSONFormat() const
{
QJsonObject jsonObj;
for (const auto &rule : rules())
for (const auto &rule : copyAsConst(rules()))
jsonObj.insert(rule.name(), rule.toJsonObject());
return QJsonDocument(jsonObj).toJson();
@ -247,15 +248,14 @@ QByteArray AutoDownloader::exportRulesToJSONFormat() const @@ -247,15 +248,14 @@ QByteArray AutoDownloader::exportRulesToJSONFormat() const
void AutoDownloader::importRulesFromJSONFormat(const QByteArray &data)
{
const auto rules = rulesFromJSON(data);
for (const auto &rule : rules)
for (const auto &rule : copyAsConst(rulesFromJSON(data)))
insertRule(rule);
}
QByteArray AutoDownloader::exportRulesToLegacyFormat() const
{
QVariantHash dict;
for (const auto &rule : rules())
for (const auto &rule : copyAsConst(rules()))
dict[rule.name()] = rule.toLegacyDict();
QByteArray data;

5
src/base/rss/rss_folder.cpp

@ -33,6 +33,7 @@ @@ -33,6 +33,7 @@
#include <QJsonObject>
#include <QJsonValue>
#include "base/global.h"
#include "rss_article.h"
using namespace RSS;
@ -122,7 +123,7 @@ void Folder::addItem(Item *item) @@ -122,7 +123,7 @@ void Folder::addItem(Item *item)
connect(item, &Item::articleAboutToBeRemoved, this, &Item::articleAboutToBeRemoved);
connect(item, &Item::unreadCountChanged, this, &Folder::handleItemUnreadCountChanged);
for (auto article: item->articles())
for (auto article: copyAsConst(item->articles()))
emit newArticle(article);
if (item->unreadCount() > 0)
@ -133,7 +134,7 @@ void Folder::removeItem(Item *item) @@ -133,7 +134,7 @@ void Folder::removeItem(Item *item)
{
Q_ASSERT(m_items.contains(item));
for (auto article: item->articles())
for (auto article: copyAsConst(item->articles()))
emit articleAboutToBeRemoved(article);
item->disconnect(this);

3
src/base/utils/fs.cpp

@ -55,6 +55,7 @@ @@ -55,6 +55,7 @@
#endif
#include "base/bittorrent/torrenthandle.h"
#include "base/global.h"
/**
* Converts a path to a string suitable for display.
@ -128,7 +129,7 @@ bool Utils::Fs::smartRemoveEmptyFolderTree(const QString &path) @@ -128,7 +129,7 @@ bool Utils::Fs::smartRemoveEmptyFolderTree(const QString &path)
std::sort(dirList.begin(), dirList.end()
, [](const QString &l, const QString &r) { return l.count("/") > r.count("/"); });
for (const QString &p : dirList) {
for (const QString &p : qAsConst(dirList)) {
// remove unwanted files
for (const QString &f : deleteFilesList) {
forceRemove(p + f);

5
src/gui/ipsubnetwhitelistoptionsdialog.cpp

@ -34,6 +34,7 @@ @@ -34,6 +34,7 @@
#include <QSortFilterProxyModel>
#include <QStringListModel>
#include "base/global.h"
#include "base/preferences.h"
#include "base/utils/net.h"
#include "ui_ipsubnetwhitelistoptionsdialog.h"
@ -47,7 +48,7 @@ IPSubnetWhitelistOptionsDialog::IPSubnetWhitelistOptionsDialog(QWidget *parent) @@ -47,7 +48,7 @@ IPSubnetWhitelistOptionsDialog::IPSubnetWhitelistOptionsDialog(QWidget *parent)
m_ui->setupUi(this);
QStringList authSubnetWhitelistStringList;
for (const Utils::Net::Subnet &subnet : Preferences::instance()->getWebUiAuthSubnetWhitelist())
for (const Utils::Net::Subnet &subnet : copyAsConst(Preferences::instance()->getWebUiAuthSubnetWhitelist()))
authSubnetWhitelistStringList << Utils::Net::subnetToString(subnet);
m_model = new QStringListModel(authSubnetWhitelistStringList, this);
@ -100,7 +101,7 @@ void IPSubnetWhitelistOptionsDialog::on_buttonWhitelistIPSubnet_clicked() @@ -100,7 +101,7 @@ void IPSubnetWhitelistOptionsDialog::on_buttonWhitelistIPSubnet_clicked()
void IPSubnetWhitelistOptionsDialog::on_buttonDeleteIPSubnet_clicked()
{
for (const auto &i : m_ui->whitelistedIPSubnetList->selectionModel()->selectedIndexes())
for (const auto &i : copyAsConst(m_ui->whitelistedIPSubnetList->selectionModel()->selectedIndexes()))
m_sortFilter->removeRow(i.row());
m_modified = true;

5
src/gui/properties/speedplotview.cpp

@ -30,6 +30,7 @@ @@ -30,6 +30,7 @@
#include <QPainter>
#include <QPen>
#include "base/global.h"
#include "base/utils/misc.h"
SpeedPlotView::SpeedPlotView(QWidget *parent)
@ -257,7 +258,7 @@ void SpeedPlotView::paintEvent(QPaintEvent *) @@ -257,7 +258,7 @@ void SpeedPlotView::paintEvent(QPaintEvent *)
double legendHeight = 0;
int legendWidth = 0;
for (const auto &property : m_properties) {
for (const auto &property : qAsConst(m_properties)) {
if (!property.enable)
continue;
@ -272,7 +273,7 @@ void SpeedPlotView::paintEvent(QPaintEvent *) @@ -272,7 +273,7 @@ void SpeedPlotView::paintEvent(QPaintEvent *)
painter.fillRect(legendBackgroundRect, legendBackgroundColor);
i = 0;
for (const auto &property : m_properties) {
for (const auto &property : qAsConst(m_properties)) {
if (!property.enable)
continue;

3
src/webui/api/appcontroller.cpp

@ -45,6 +45,7 @@ @@ -45,6 +45,7 @@
#endif
#include "base/bittorrent/session.h"
#include "base/global.h"
#include "base/net/portforwarder.h"
#include "base/net/proxyconfigurationmanager.h"
#include "base/preferences.h"
@ -200,7 +201,7 @@ void AppController::preferencesAction() @@ -200,7 +201,7 @@ void AppController::preferencesAction()
data["bypass_local_auth"] = !pref->isWebUiLocalAuthEnabled();
data["bypass_auth_subnet_whitelist_enabled"] = pref->isWebUiAuthSubnetWhitelistEnabled();
QStringList authSubnetWhitelistStringList;
for (const Utils::Net::Subnet &subnet : pref->getWebUiAuthSubnetWhitelist())
for (const Utils::Net::Subnet &subnet : copyAsConst(pref->getWebUiAuthSubnetWhitelist()))
authSubnetWhitelistStringList << Utils::Net::subnetToString(subnet);
data["bypass_auth_subnet_whitelist"] = authSubnetWhitelistStringList.join("\n");
// Update my dynamic domain name

Loading…
Cancel
Save