QFileSystemWatcherEngines: port some Java-style iterators to ranged-for

Java-style iterators are scheduled to be deprecated.

The general pattern used in the patch is that instead of copying an
input list, then iterating over the copy with some calls to
it.remove() (which leads to quadratic-complexity loops), we simply
copy conditionally (a la remove_copy_if instead of remove_if).

To make clearer what's going on, rename the outgoing list to
'unhandled'.

To avoid having to touch too much of the loops' structure, which
sometimes is quite convoluted, use qScopeGuard to do the append to
'unhandled', unless the original code removed the element.

Saves a surprising almost 5KiB in text size on GCC 9.1 optimized
AMD64 Linux builds.

Change-Id: Ifd861de9aa48d66b420858606998dd08a8401e03
Reviewed-by: Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
Marc Mutz 2019-05-19 23:25:12 +02:00
parent 4e026a2076
commit b03385f9cf
4 changed files with 52 additions and 53 deletions

View File

@ -46,6 +46,7 @@
#include <qdebug.h>
#include <qfile.h>
#include <qfileinfo.h>
#include <qscopeguard.h>
#include <qsocketnotifier.h>
#include <qvarlengtharray.h>
@ -268,12 +269,11 @@ QStringList QInotifyFileSystemWatcherEngine::addPaths(const QStringList &paths,
QStringList *files,
QStringList *directories)
{
QStringList p = paths;
QMutableListIterator<QString> it(p);
while (it.hasNext()) {
QString path = it.next();
QStringList unhandled;
for (const QString &path : paths) {
QFileInfo fi(path);
bool isDir = fi.isDir();
auto sg = qScopeGuard([&]{ unhandled.push_back(path); });
if (isDir) {
if (directories->contains(path))
continue;
@ -305,7 +305,7 @@ QStringList QInotifyFileSystemWatcherEngine::addPaths(const QStringList &paths,
continue;
}
it.remove();
sg.dismiss();
int id = isDir ? -wd : wd;
if (id < 0) {
@ -318,19 +318,19 @@ QStringList QInotifyFileSystemWatcherEngine::addPaths(const QStringList &paths,
idToPath.insert(id, path);
}
return p;
return unhandled;
}
QStringList QInotifyFileSystemWatcherEngine::removePaths(const QStringList &paths,
QStringList *files,
QStringList *directories)
{
QStringList p = paths;
QMutableListIterator<QString> it(p);
while (it.hasNext()) {
QString path = it.next();
QStringList unhandled;
for (const QString &path : paths) {
int id = pathToID.take(path);
auto sg = qScopeGuard([&]{ unhandled.push_back(path); });
// Multiple paths could be associated to the same watch descriptor
// when a file is moved and added with the new name.
// So we should find and delete the correct one by using
@ -349,7 +349,8 @@ QStringList QInotifyFileSystemWatcherEngine::removePaths(const QStringList &path
inotify_rm_watch(inotifyFd, wd);
}
it.remove();
sg.dismiss();
if (id < 0) {
directories->removeAll(path);
} else {
@ -357,7 +358,7 @@ QStringList QInotifyFileSystemWatcherEngine::removePaths(const QStringList &path
}
}
return p;
return unhandled;
}
void QInotifyFileSystemWatcherEngine::readFromInotify()

View File

@ -45,6 +45,7 @@
#include <qdebug.h>
#include <qfile.h>
#include <qscopeguard.h>
#include <qsocketnotifier.h>
#include <qvarlengtharray.h>
@ -94,10 +95,9 @@ QStringList QKqueueFileSystemWatcherEngine::addPaths(const QStringList &paths,
QStringList *files,
QStringList *directories)
{
QStringList p = paths;
QMutableListIterator<QString> it(p);
while (it.hasNext()) {
QString path = it.next();
QStringList unhandled;
for (const QString &path : paths) {
auto sg = qScopeGuard([&]{unhandled.push_back(path);});
int fd;
#if defined(O_EVTONLY)
fd = qt_safe_open(QFile::encodeName(path), O_EVTONLY);
@ -149,7 +149,8 @@ QStringList QKqueueFileSystemWatcherEngine::addPaths(const QStringList &paths,
continue;
}
it.remove();
sg.dismiss();
if (id < 0) {
DEBUG() << "QKqueueFileSystemWatcherEngine: added directory path" << path;
directories->append(path);
@ -162,20 +163,19 @@ QStringList QKqueueFileSystemWatcherEngine::addPaths(const QStringList &paths,
idToPath.insert(id, path);
}
return p;
return unhandled;
}
QStringList QKqueueFileSystemWatcherEngine::removePaths(const QStringList &paths,
QStringList *files,
QStringList *directories)
{
QStringList p = paths;
if (pathToID.isEmpty())
return p;
return paths;
QMutableListIterator<QString> it(p);
while (it.hasNext()) {
QString path = it.next();
QStringList unhandled;
for (const QString &path : paths) {
auto sg = qScopeGuard([&]{unhandled.push_back(path);});
int id = pathToID.take(path);
QString x = idToPath.take(id);
if (x.isEmpty() || x != path)
@ -183,14 +183,15 @@ QStringList QKqueueFileSystemWatcherEngine::removePaths(const QStringList &paths
::close(id < 0 ? -id : id);
it.remove();
sg.dismiss();
if (id < 0)
directories->removeAll(path);
else
files->removeAll(path);
}
return p;
return unhandled;
}
void QKqueueFileSystemWatcherEngine::readFromKqueue()

View File

@ -38,6 +38,7 @@
****************************************************************************/
#include "qfilesystemwatcher_polling_p.h"
#include <QtCore/qscopeguard.h>
#include <QtCore/qtimer.h>
QT_BEGIN_NAMESPACE
@ -53,10 +54,9 @@ QStringList QPollingFileSystemWatcherEngine::addPaths(const QStringList &paths,
QStringList *files,
QStringList *directories)
{
QStringList p = paths;
QMutableListIterator<QString> it(p);
while (it.hasNext()) {
QString path = it.next();
QStringList unhandled;
for (const QString &path : paths) {
auto sg = qScopeGuard([&]{ unhandled.push_back(path); });
QFileInfo fi(path);
if (!fi.exists())
continue;
@ -73,7 +73,7 @@ QStringList QPollingFileSystemWatcherEngine::addPaths(const QStringList &paths,
files->append(path);
this->files.insert(path, fi);
}
it.remove();
sg.dismiss();
}
if ((!this->files.isEmpty() ||
@ -82,23 +82,21 @@ QStringList QPollingFileSystemWatcherEngine::addPaths(const QStringList &paths,
timer.start(PollingInterval);
}
return p;
return unhandled;
}
QStringList QPollingFileSystemWatcherEngine::removePaths(const QStringList &paths,
QStringList *files,
QStringList *directories)
{
QStringList p = paths;
QMutableListIterator<QString> it(p);
while (it.hasNext()) {
QString path = it.next();
QStringList unhandled;
for (const QString &path : paths) {
if (this->directories.remove(path)) {
directories->removeAll(path);
it.remove();
} else if (this->files.remove(path)) {
files->removeAll(path);
it.remove();
} else {
unhandled.push_back(path);
}
}
@ -107,7 +105,7 @@ QStringList QPollingFileSystemWatcherEngine::removePaths(const QStringList &path
timer.stop();
}
return p;
return unhandled;
}
void QPollingFileSystemWatcherEngine::timeout()

View File

@ -44,6 +44,7 @@
#include <qfileinfo.h>
#include <qstringlist.h>
#include <qset.h>
#include <qscopeguard.h>
#include <qdatetime.h>
#include <qdir.h>
#include <qtextstream.h>
@ -377,10 +378,9 @@ QStringList QWindowsFileSystemWatcherEngine::addPaths(const QStringList &paths,
QStringList *directories)
{
DEBUG() << "Adding" << paths.count() << "to existing" << (files->count() + directories->count()) << "watchers";
QStringList p = paths;
QMutableListIterator<QString> it(p);
while (it.hasNext()) {
QString path = it.next();
QStringList unhandled;
for (const QString &path : paths) {
auto sg = qScopeGuard([&] { unhandled.push_back(path); });
QString normalPath = path;
if ((normalPath.endsWith(QLatin1Char('/')) && !normalPath.endsWith(QLatin1String(":/")))
|| (normalPath.endsWith(QLatin1Char('\\')) && !normalPath.endsWith(QLatin1String(":\\")))) {
@ -463,7 +463,7 @@ QStringList QWindowsFileSystemWatcherEngine::addPaths(const QStringList &paths,
else
files->append(path);
}
it.remove();
sg.dismiss();
thread->wakeup();
break;
}
@ -493,7 +493,7 @@ QStringList QWindowsFileSystemWatcherEngine::addPaths(const QStringList &paths,
else
files->append(path);
it.remove();
sg.dismiss();
found = true;
thread->wakeup();
break;
@ -519,7 +519,7 @@ QStringList QWindowsFileSystemWatcherEngine::addPaths(const QStringList &paths,
thread->msg = '@';
thread->start();
threads.append(thread);
it.remove();
sg.dismiss();
}
}
}
@ -527,12 +527,12 @@ QStringList QWindowsFileSystemWatcherEngine::addPaths(const QStringList &paths,
#ifndef Q_OS_WINRT
if (Q_LIKELY(m_driveListener)) {
for (const QString &path : paths) {
if (!p.contains(path))
if (!unhandled.contains(path))
m_driveListener->addPath(path);
}
}
#endif // !Q_OS_WINRT
return p;
return unhandled;
}
QStringList QWindowsFileSystemWatcherEngine::removePaths(const QStringList &paths,
@ -540,10 +540,9 @@ QStringList QWindowsFileSystemWatcherEngine::removePaths(const QStringList &path
QStringList *directories)
{
DEBUG() << "removePaths" << paths;
QStringList p = paths;
QMutableListIterator<QString> it(p);
while (it.hasNext()) {
QString path = it.next();
QStringList unhandled;
for (const QString &path : paths) {
auto sg = qScopeGuard([&] { unhandled.push_back(path); });
QString normalPath = path;
if (normalPath.endsWith(QLatin1Char('/')) || normalPath.endsWith(QLatin1Char('\\')))
normalPath.chop(1);
@ -572,7 +571,7 @@ QStringList QWindowsFileSystemWatcherEngine::removePaths(const QStringList &path
// ###
files->removeAll(path);
directories->removeAll(path);
it.remove();
sg.dismiss();
if (h.isEmpty()) {
DEBUG() << "Closing handle" << handle.handle;
@ -613,7 +612,7 @@ QStringList QWindowsFileSystemWatcherEngine::removePaths(const QStringList &path
}
threads.removeAll(0);
return p;
return unhandled;
}
///////////