diff options
Diffstat (limited to 'src/corelib/io/qdir.cpp')
-rw-r--r-- | src/corelib/io/qdir.cpp | 173 |
1 files changed, 107 insertions, 66 deletions
diff --git a/src/corelib/io/qdir.cpp b/src/corelib/io/qdir.cpp index b08595bf14..05947f3380 100644 --- a/src/corelib/io/qdir.cpp +++ b/src/corelib/io/qdir.cpp @@ -9,7 +9,7 @@ #ifndef QT_NO_DEBUG_STREAM #include "qdebug.h" #endif -#include "qdiriterator.h" +#include "qdirlisting.h" #include "qdatetime.h" #include "qstring.h" #if QT_CONFIG(regularexpression) @@ -22,6 +22,7 @@ #include <qstringbuilder.h> #ifndef QT_BOOTSTRAPPED +# include <qcollator.h> # include "qreadwritelock.h" # include "qmutex.h" #endif @@ -199,10 +200,8 @@ struct QDirSortItem // A dir e.g. "dirA.bar" doesn't have actually have an extension/suffix, when // sorting by type such "suffix" should be ignored but that would complicate // the code and uses can change the behavior by setting DirsFirst/DirsLast - if (sort.testAnyFlag(QDir::Type)) { - const bool ic = sort.testAnyFlag(QDir::IgnoreCase); - suffix_cache = ic ? item.suffix().toLower() : item.suffix(); - } + if (sort.testAnyFlag(QDir::Type)) + suffix_cache = item.suffix(); } mutable QString filename_cache; @@ -210,13 +209,39 @@ struct QDirSortItem QFileInfo item; }; - class QDirSortItemComparator { QDir::SortFlags qt_cmp_si_sort_flags; + +#ifndef QT_BOOTSTRAPPED + QCollator *collator = nullptr; +#endif public: - QDirSortItemComparator(QDir::SortFlags flags) : qt_cmp_si_sort_flags(flags) {} +#ifndef QT_BOOTSTRAPPED + QDirSortItemComparator(QDir::SortFlags flags, QCollator *coll = nullptr) + : qt_cmp_si_sort_flags(flags), collator(coll) + { + Q_ASSERT(!qt_cmp_si_sort_flags.testAnyFlag(QDir::LocaleAware) || collator); + + if (collator && qt_cmp_si_sort_flags.testAnyFlag(QDir::IgnoreCase)) + collator->setCaseSensitivity(Qt::CaseInsensitive); + } +#else + QDirSortItemComparator(QDir::SortFlags flags) + : qt_cmp_si_sort_flags(flags) + { + } +#endif bool operator()(const QDirSortItem &, const QDirSortItem &) const; + + int compareStrings(const QString &a, const QString &b, Qt::CaseSensitivity cs) const + { +#ifndef QT_BOOTSTRAPPED + if (collator) + return collator->compare(a, b); +#endif + return a.compare(b, cs); + } }; bool QDirSortItemComparator::operator()(const QDirSortItem &n1, const QDirSortItem &n2) const @@ -229,6 +254,9 @@ bool QDirSortItemComparator::operator()(const QDirSortItem &n1, const QDirSortIt if ((qt_cmp_si_sort_flags & QDir::DirsLast) && (f1->item.isDir() != f2->item.isDir())) return !f1->item.isDir(); + const bool ic = qt_cmp_si_sort_flags.testAnyFlag(QDir::IgnoreCase); + const auto qtcase = ic ? Qt::CaseInsensitive : Qt::CaseSensitive; + qint64 r = 0; int sortBy = ((qt_cmp_si_sort_flags & QDir::SortByMask) | (qt_cmp_si_sort_flags & QDir::Type)).toInt(); @@ -243,11 +271,8 @@ bool QDirSortItemComparator::operator()(const QDirSortItem &n1, const QDirSortIt case QDir::Size: r = f2->item.size() - f1->item.size(); break; - case QDir::Type: { - r = qt_cmp_si_sort_flags & QDir::LocaleAware - ? f1->suffix_cache.localeAwareCompare(f2->suffix_cache) - : f1->suffix_cache.compare(f2->suffix_cache); - } + case QDir::Type: + r = compareStrings(f1->suffix_cache, f2->suffix_cache, qtcase); break; default: ; @@ -255,18 +280,13 @@ bool QDirSortItemComparator::operator()(const QDirSortItem &n1, const QDirSortIt if (r == 0 && sortBy != QDir::Unsorted) { // Still not sorted - sort by name - bool ic = qt_cmp_si_sort_flags.testAnyFlag(QDir::IgnoreCase); if (f1->filename_cache.isNull()) - f1->filename_cache = ic ? f1->item.fileName().toLower() - : f1->item.fileName(); + f1->filename_cache = f1->item.fileName(); if (f2->filename_cache.isNull()) - f2->filename_cache = ic ? f2->item.fileName().toLower() - : f2->item.fileName(); + f2->filename_cache = f2->item.fileName(); - r = qt_cmp_si_sort_flags & QDir::LocaleAware - ? f1->filename_cache.localeAwareCompare(f2->filename_cache) - : f1->filename_cache.compare(f2->filename_cache); + r = compareStrings(f1->filename_cache, f2->filename_cache, qtcase); } if (qt_cmp_si_sort_flags & QDir::Reversed) return r > 0; @@ -293,28 +313,42 @@ inline void QDirPrivate::sortFileList(QDir::SortFlags sort, const QFileInfoList names->append(fi.fileName()); } } else { - QScopedArrayPointer<QDirSortItem> si(new QDirSortItem[n]); + QVarLengthArray<QDirSortItem, 64> si; + si.reserve(n); for (qsizetype i = 0; i < n; ++i) - si[i] = QDirSortItem{l.at(i), sort}; + si.emplace_back(l.at(i), sort); +#ifndef QT_BOOTSTRAPPED + if (sort.testAnyFlag(QDir::LocaleAware)) { + QCollator coll; + std::sort(si.data(), si.data() + n, QDirSortItemComparator(sort, &coll)); + } else { + std::sort(si.data(), si.data() + n, QDirSortItemComparator(sort)); + } +#else std::sort(si.data(), si.data() + n, QDirSortItemComparator(sort)); +#endif // QT_BOOTSTRAPPED + // put them back in the list(s) for (qsizetype i = 0; i < n; ++i) { + auto &fileInfo = si[i].item; if (infos) - infos->append(si[i].item); - if (names) - names->append(si[i].item.fileName()); + infos->append(fileInfo); + if (names) { + const bool cached = !si[i].filename_cache.isNull(); + names->append(cached ? si[i].filename_cache : fileInfo.fileName()); + } } } } + inline void QDirPrivate::initFileLists(const QDir &dir) const { QMutexLocker locker(&fileCache.mutex); if (!fileCache.fileListsInitialized) { QFileInfoList l; - QDirIterator it(dir); - while (it.hasNext()) - l.append(it.nextFileInfo()); + for (const auto &dirEntry : QDirListing(dir)) + l.emplace_back(dirEntry.fileInfo()); sortFileList(sort, l, &fileCache.files, &fileCache.fileInfos); fileCache.fileListsInitialized = true; @@ -329,8 +363,7 @@ inline void QDirPrivate::clearCache(MetaDataClearing mode) fileCache.fileListsInitialized = false; fileCache.files.clear(); fileCache.fileInfos.clear(); - fileEngine.reset( - QFileSystemEngine::resolveEntryAndCreateLegacyEngine(dirEntry, fileCache.metaData)); + fileEngine = QFileSystemEngine::createLegacyEngine(dirEntry, fileCache.metaData); } /*! @@ -342,6 +375,7 @@ inline void QDirPrivate::clearCache(MetaDataClearing mode) \ingroup shared \reentrant + \compares equality A QDir is used to manipulate path names, access information regarding paths and files, and manipulate the underlying file @@ -513,7 +547,8 @@ inline void QDirPrivate::clearCache(MetaDataClearing mode) \include android-content-uri-limitations.qdocinc - \sa QFileInfo, QFile, QFileDialog, QCoreApplication::applicationDirPath(), {Find Files Example} + \sa QFileInfo, QFile, QFileDialog, QCoreApplication::applicationDirPath(), + {Fetch More Example} */ /*! @@ -632,7 +667,10 @@ QString QDir::path() const QString QDir::absolutePath() const { Q_D(const QDir); - return d->resolveAbsoluteEntry(); + if (!d->fileEngine) + return d->resolveAbsoluteEntry(); + + return d->fileEngine->fileName(QAbstractFileEngine::AbsoluteName); } /*! @@ -1256,6 +1294,7 @@ QDir::SortFlags QDir::sorting() const after the directories, again in reverse order. */ +#ifndef QT_BOOTSTRAPPED /*! Sets the sort order used by entryList() and entryInfoList(). @@ -1388,18 +1427,16 @@ QStringList QDir::entryList(const QStringList &nameFilters, Filters filters, } } - QDirIterator it(d->dirEntry.filePath(), nameFilters, filters); + QDirListing dirList(d->dirEntry.filePath(), nameFilters, filters); QStringList ret; if (needsSorting) { QFileInfoList l; - while (it.hasNext()) - l.append(it.nextFileInfo()); + for (const auto &dirEntry : dirList) + l.emplace_back(dirEntry.fileInfo()); d->sortFileList(sort, l, &ret, nullptr); } else { - while (it.hasNext()) { - it.next(); - ret.append(it.fileName()); - } + for (const auto &dirEntry : dirList) + ret.emplace_back(dirEntry.fileName()); } return ret; } @@ -1436,13 +1473,13 @@ QFileInfoList QDir::entryInfoList(const QStringList &nameFilters, Filters filter } QFileInfoList l; - QDirIterator it(d->dirEntry.filePath(), nameFilters, filters); - while (it.hasNext()) - l.append(it.nextFileInfo()); + for (const auto &dirEntry : QDirListing(d->dirEntry.filePath(), nameFilters, filters)) + l.emplace_back(dirEntry.fileInfo()); QFileInfoList ret; d->sortFileList(sort, l, nullptr, &ret); return ret; } +#endif // !QT_BOOTSTRAPPED /*! Creates a sub-directory called \a dirName. @@ -1579,6 +1616,7 @@ bool QDir::rmpath(const QString &dirPath) const return d->fileEngine->rmdir(fn, true); } +#ifndef QT_BOOTSTRAPPED /*! \since 5.0 Removes the directory, including all its contents. @@ -1607,12 +1645,11 @@ bool QDir::removeRecursively() bool success = true; const QString dirPath = path(); // not empty -- we must empty it first - QDirIterator di(dirPath, QDir::AllEntries | QDir::Hidden | QDir::System | QDir::NoDotAndDotDot); - while (di.hasNext()) { - const QFileInfo fi = di.nextFileInfo(); - const QString &filePath = di.filePath(); + constexpr auto dirFilters = QDir::AllEntries | QDir::Hidden | QDir::System | QDir::NoDotAndDotDot; + for (const auto &dirEntry : QDirListing(dirPath, dirFilters)) { + const QString &filePath = dirEntry.filePath(); bool ok; - if (fi.isDir() && !fi.isSymLink()) { + if (dirEntry.isDir() && !dirEntry.isSymLink()) { ok = QDir(filePath).removeRecursively(); // recursive } else { ok = QFile::remove(filePath); @@ -1632,6 +1669,7 @@ bool QDir::removeRecursively() return success; } +#endif // !QT_BOOTSTRAPPED /*! Returns \c true if the directory is readable \e and we can open files @@ -1768,7 +1806,9 @@ bool QDir::makeAbsolute() } /*! - Returns \c true if directory \a dir and this directory have the same + \fn bool QDir::operator==(const QDir &lhs, const QDir &rhs) + + Returns \c true if directory \a lhs and directory \a rhs have the same path and their sort and filter settings are the same; otherwise returns \c false. @@ -1776,10 +1816,10 @@ bool QDir::makeAbsolute() \snippet code/src_corelib_io_qdir.cpp 10 */ -bool QDir::operator==(const QDir &dir) const +bool comparesEqual(const QDir &lhs, const QDir &rhs) { - Q_D(const QDir); - const QDirPrivate *other = dir.d_ptr.constData(); + const QDirPrivate *d = lhs.d_ptr.constData(); + const QDirPrivate *other = rhs.d_ptr.constData(); if (d == other) return true; @@ -1803,13 +1843,13 @@ bool QDir::operator==(const QDir &dir) const if (d->dirEntry.filePath() == other->dirEntry.filePath()) return true; - if (exists()) { - if (!dir.exists()) + if (lhs.exists()) { + if (!rhs.exists()) return false; //can't be equal if only one exists // Both exist, fallback to expensive canonical path computation - return canonicalPath().compare(dir.canonicalPath(), sensitive) == 0; + return lhs.canonicalPath().compare(rhs.canonicalPath(), sensitive) == 0; } else { - if (dir.exists()) + if (rhs.exists()) return false; //can't be equal if only one exists // Neither exists, compare absolute paths rather than canonical (which would be empty strings) QString thisFilePath = d->resolveAbsoluteEntry(); @@ -1839,11 +1879,10 @@ QDir &QDir::operator=(const QDir &dir) */ /*! - \fn bool QDir::operator!=(const QDir &dir) const + \fn bool QDir::operator!=(const QDir &lhs, const QDir &rhs) - Returns \c true if directory \a dir and this directory have different - paths or different sort or filter settings; otherwise returns - false. + Returns \c true if directory \a lhs and directory \a rhs have different + paths or different sort or filter settings; otherwise returns \c false. Example: @@ -1913,6 +1952,7 @@ bool QDir::exists(const QString &name) const return QFileInfo::exists(filePath(name)); } +#ifndef QT_BOOTSTRAPPED /*! Returns whether the directory is empty. @@ -1929,9 +1969,10 @@ bool QDir::exists(const QString &name) const bool QDir::isEmpty(Filters filters) const { Q_D(const QDir); - QDirIterator it(d->dirEntry.filePath(), d->nameFilters, filters); - return !it.hasNext(); + QDirListing dirList(d->dirEntry.filePath(), d->nameFilters, filters); + return dirList.cbegin() == dirList.cend(); } +#endif // !QT_BOOTSTRAPPED /*! Returns a list of the root directories on this system. @@ -2179,8 +2220,8 @@ QString qt_normalizePathSegments(const QString &name, QDirPrivate::PathNormaliza QVarLengthArray<char16_t> outVector(len); qsizetype used = len; char16_t *out = outVector.data(); - const ushort *p = reinterpret_cast<const ushort *>(name.data()); - const ushort *prefix = p; + const char16_t *p = reinterpret_cast<const char16_t *>(name.data()); + const char16_t *prefix = p; qsizetype up = 0; const qsizetype prefixLength = rootLength(name, allowUncPaths); @@ -2194,10 +2235,10 @@ QString qt_normalizePathSegments(const QString &name, QDirPrivate::PathNormaliza --i; } - auto isDot = [](const ushort *p, qsizetype i) { + auto isDot = [](const char16_t *p, qsizetype i) { return i > 1 && p[i - 1] == '.' && p[i - 2] == '/'; }; - auto isDotDot = [](const ushort *p, qsizetype i) { + auto isDotDot = [](const char16_t *p, qsizetype i) { return i > 2 && p[i - 1] == '.' && p[i - 2] == '.' && p[i - 3] == '/'; }; @@ -2318,7 +2359,7 @@ QString qt_normalizePathSegments(const QString &name, QDirPrivate::PathNormaliza // If path was not modified return the original value if (used == 0) return name; - return QString::fromUtf16(out + used, len - used); + return QStringView(out + used, len - used).toString(); } static QString qt_cleanPath(const QString &path, bool *ok) |