use Floyd cycle detection

This commit is contained in:
Marco Martin 2014-09-01 15:15:54 +02:00
parent 21cf68dbd2
commit 55a6095138
2 changed files with 26 additions and 1 deletions

View File

@ -193,7 +193,8 @@ void Package::setFallbackPackage(const Plasma::Package &package)
{
if ((d->fallbackPackage && d->fallbackPackage->path() == package.path() && d->fallbackPackage->metadata() == package.metadata()) ||
//can't be fallback of itself
(package.path() == path() && package.metadata() == metadata())) {
(package.path() == path() && package.metadata() == metadata()) ||
d->hasCycle(package)) {
return;
}
@ -908,4 +909,27 @@ QString PackagePrivate::fallbackFilePath(const char *key, const QString &filenam
}
}
bool PackagePrivate::hasCycle(const Plasma::Package &package)
{
if (!package.d->fallbackPackage) {
return false;
}
//This is the Floyd cycle detection algorithm
//http://en.wikipedia.org/wiki/Cycle_detection#Tortoise_and_hare
const Plasma::Package *slowPackage = &package;
const Plasma::Package *fastPackage = &package;
while (fastPackage && fastPackage->d->fallbackPackage) {
//consider two packages the same if they have the same metadata
if ((fastPackage->d->fallbackPackage->metadata().isValid() && fastPackage->d->fallbackPackage->metadata() == slowPackage->metadata()) ||
(fastPackage->d->fallbackPackage->d->fallbackPackage->metadata().isValid() && fastPackage->d->fallbackPackage->d->fallbackPackage->metadata() == slowPackage->metadata())) {
return true;
}
fastPackage = fastPackage->d->fallbackPackage->d->fallbackPackage;
slowPackage = slowPackage->d->fallbackPackage;
}
return false;
}
} // Namespace

View File

@ -74,6 +74,7 @@ public:
QString unpack(const QString &filePath);
void updateHash(const QString &basePath, const QString &subPath, const QDir &dir, QCryptographicHash &hash);
QString fallbackFilePath(const char *key, const QString &filename = QString()) const;
bool hasCycle(const Plasma::Package &package);
QWeakPointer<PackageStructure> structure;
QString path;