diff --git a/autotests/udsentrytest.cpp b/autotests/udsentrytest.cpp index 3d19870a..59279d74 100644 --- a/autotests/udsentrytest.cpp +++ b/autotests/udsentrytest.cpp @@ -1,264 +1,334 @@ /* This file is part of the KDE project Copyright (C) 2013 Frank Reininghaus This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "udsentrytest.h" #include #include #include #include #include #include #include #include "kiotesthelper.h" struct UDSTestField { UDSTestField() {} UDSTestField(uint uds, const QString &value) : m_uds(uds), m_string(value) { Q_ASSERT(uds & KIO::UDSEntry::UDS_STRING); } UDSTestField(uint uds, long long value) : m_uds(uds), m_long(value) { Q_ASSERT(uds & KIO::UDSEntry::UDS_NUMBER); } uint m_uds; QString m_string; long long m_long; }; /** * Test that storing UDSEntries to a stream and then re-loading them works. */ void UDSEntryTest::testSaveLoad() { QVector > testCases { // Data for 1st UDSEntry. { UDSTestField(KIO::UDSEntry::UDS_SIZE, 1), UDSTestField(KIO::UDSEntry::UDS_USER, QStringLiteral("user1")), UDSTestField(KIO::UDSEntry::UDS_GROUP, QStringLiteral("group1")), UDSTestField(KIO::UDSEntry::UDS_NAME, QStringLiteral("filename1")), UDSTestField(KIO::UDSEntry::UDS_MODIFICATION_TIME, 123456), UDSTestField(KIO::UDSEntry::UDS_CREATION_TIME, 12345), UDSTestField(KIO::UDSEntry::UDS_DEVICE_ID, 2), UDSTestField(KIO::UDSEntry::UDS_INODE, 56) }, // 2nd entry: change some of the data. { UDSTestField(KIO::UDSEntry::UDS_SIZE, 2), UDSTestField(KIO::UDSEntry::UDS_USER, QStringLiteral("user2")), UDSTestField(KIO::UDSEntry::UDS_GROUP, QStringLiteral("group1")), UDSTestField(KIO::UDSEntry::UDS_NAME, QStringLiteral("filename2")), UDSTestField(KIO::UDSEntry::UDS_MODIFICATION_TIME, 12345), UDSTestField(KIO::UDSEntry::UDS_CREATION_TIME, 1234), UDSTestField(KIO::UDSEntry::UDS_DEVICE_ID, 87), UDSTestField(KIO::UDSEntry::UDS_INODE, 42) }, // 3rd entry: keep the data, but change the order of the entries. { UDSTestField(KIO::UDSEntry::UDS_SIZE, 2), UDSTestField(KIO::UDSEntry::UDS_GROUP, QStringLiteral("group1")), UDSTestField(KIO::UDSEntry::UDS_USER, QStringLiteral("user2")), UDSTestField(KIO::UDSEntry::UDS_NAME, QStringLiteral("filename2")), UDSTestField(KIO::UDSEntry::UDS_MODIFICATION_TIME, 12345), UDSTestField(KIO::UDSEntry::UDS_DEVICE_ID, 87), UDSTestField(KIO::UDSEntry::UDS_INODE, 42), UDSTestField(KIO::UDSEntry::UDS_CREATION_TIME, 1234), }, // 4th entry: change some of the data and the order of the entries. { UDSTestField(KIO::UDSEntry::UDS_SIZE, 2), UDSTestField(KIO::UDSEntry::UDS_USER, QStringLiteral("user4")), UDSTestField(KIO::UDSEntry::UDS_GROUP, QStringLiteral("group4")), UDSTestField(KIO::UDSEntry::UDS_MODIFICATION_TIME, 12346), UDSTestField(KIO::UDSEntry::UDS_DEVICE_ID, 87), UDSTestField(KIO::UDSEntry::UDS_INODE, 42), UDSTestField(KIO::UDSEntry::UDS_CREATION_TIME, 1235), UDSTestField(KIO::UDSEntry::UDS_NAME, QStringLiteral("filename4")) }, // 5th entry: remove one field. { UDSTestField(KIO::UDSEntry::UDS_SIZE, 2), UDSTestField(KIO::UDSEntry::UDS_USER, QStringLiteral("user4")), UDSTestField(KIO::UDSEntry::UDS_GROUP, QStringLiteral("group4")), UDSTestField(KIO::UDSEntry::UDS_MODIFICATION_TIME, 12346), UDSTestField(KIO::UDSEntry::UDS_INODE, 42), UDSTestField(KIO::UDSEntry::UDS_CREATION_TIME, 1235), UDSTestField(KIO::UDSEntry::UDS_NAME, QStringLiteral("filename4")) }, // 6th entry: add a new field, and change some others. { UDSTestField(KIO::UDSEntry::UDS_SIZE, 89), UDSTestField(KIO::UDSEntry::UDS_ICON_NAME, QStringLiteral("icon6")), UDSTestField(KIO::UDSEntry::UDS_USER, QStringLiteral("user6")), UDSTestField(KIO::UDSEntry::UDS_GROUP, QStringLiteral("group4")), UDSTestField(KIO::UDSEntry::UDS_MODIFICATION_TIME, 12346), UDSTestField(KIO::UDSEntry::UDS_INODE, 32), UDSTestField(KIO::UDSEntry::UDS_CREATION_TIME, 1235), UDSTestField(KIO::UDSEntry::UDS_NAME, QStringLiteral("filename6")) } }; // Store the entries in a QByteArray. QByteArray data; { QDataStream stream(&data, QIODevice::WriteOnly); foreach (const QVector &testCase, testCases) { KIO::UDSEntry entry; foreach (const UDSTestField &field, testCase) { uint uds = field.m_uds; if (uds & KIO::UDSEntry::UDS_STRING) { entry.fastInsert(uds, field.m_string); } else { Q_ASSERT(uds & KIO::UDSEntry::UDS_NUMBER); entry.fastInsert(uds, field.m_long); } } QCOMPARE(entry.count(), testCase.count()); stream << entry; } } // Re-load the entries and compare with the data in testCases. { QDataStream stream(data); foreach (const QVector &testCase, testCases) { KIO::UDSEntry entry; stream >> entry; QCOMPARE(entry.count(), testCase.count()); foreach (const UDSTestField &field, testCase) { uint uds = field.m_uds; QVERIFY(entry.contains(uds)); if (uds & KIO::UDSEntry::UDS_STRING) { QCOMPARE(entry.stringValue(uds), field.m_string); } else { Q_ASSERT(uds & KIO::UDSEntry::UDS_NUMBER); QCOMPARE(entry.numberValue(uds), field.m_long); } } } } // Now: Store the fields manually in the order in which they appear in // testCases, and re-load them. This ensures that loading the entries // works no matter in which order the fields appear in the QByteArray. data.clear(); { QDataStream stream(&data, QIODevice::WriteOnly); foreach (const QVector &testCase, testCases) { stream << testCase.count(); foreach (const UDSTestField &field, testCase) { uint uds = field.m_uds; stream << uds; if (uds & KIO::UDSEntry::UDS_STRING) { stream << field.m_string; } else { Q_ASSERT(uds & KIO::UDSEntry::UDS_NUMBER); stream << field.m_long; } } } } { QDataStream stream(data); foreach (const QVector &testCase, testCases) { KIO::UDSEntry entry; stream >> entry; QCOMPARE(entry.count(), testCase.count()); foreach (const UDSTestField &field, testCase) { uint uds = field.m_uds; QVERIFY(entry.contains(uds)); if (uds & KIO::UDSEntry::UDS_STRING) { QCOMPARE(entry.stringValue(uds), field.m_string); } else { Q_ASSERT(uds & KIO::UDSEntry::UDS_NUMBER); QCOMPARE(entry.numberValue(uds), field.m_long); } } } } } /** * Test to verify that move semantics work. This is only useful when ran through callgrind. */ void UDSEntryTest::testMove() { // Create a temporary file. Just to make a UDSEntry further down. QTemporaryFile file; QVERIFY(file.open()); const QByteArray filePath = file.fileName().toLocal8Bit(); const QString fileName = QUrl(file.fileName()).fileName(); // QTemporaryFile::fileName returns the full path. QVERIFY(!fileName.isEmpty()); // We have a file now. Get the stat data from it to make the UDSEntry. QT_STATBUF statBuf; QVERIFY(QT_LSTAT(filePath.constData(), &statBuf) == 0); KIO::UDSEntry entry(statBuf, fileName); // Verify that the name in the UDSEntry is the same as we've got from the fileName var. QCOMPARE(fileName, entry.stringValue(KIO::UDSEntry::UDS_NAME)); // That was the boilerplate code. Now for move semantics. // First: move assignment. { // First a copy as we need to keep the entry for the next test. KIO::UDSEntry entryCopy = entry; // Now move-assignment (two lines to prevent compiler optimization) KIO::UDSEntry movedEntry; movedEntry = std::move(entryCopy); // And verify that this works. QCOMPARE(fileName, movedEntry.stringValue(KIO::UDSEntry::UDS_NAME)); } // Move constructor { // First a copy again KIO::UDSEntry entryCopy = entry; // Now move-assignment KIO::UDSEntry movedEntry(std::move(entryCopy)); // And verify that this works. QCOMPARE(fileName, movedEntry.stringValue(KIO::UDSEntry::UDS_NAME)); } } +/** + * Test to verify that equal semantics work. + */ +void UDSEntryTest::testEquality() +{ + KIO::UDSEntry entry; + entry.fastInsert(KIO::UDSEntry::UDS_SIZE, 1); + entry.fastInsert(KIO::UDSEntry::UDS_USER, QStringLiteral("user1")); + entry.fastInsert(KIO::UDSEntry::UDS_GROUP, QStringLiteral("group1")); + entry.fastInsert(KIO::UDSEntry::UDS_NAME, QStringLiteral("filename1")); + entry.fastInsert(KIO::UDSEntry::UDS_MODIFICATION_TIME, 123456); + entry.fastInsert(KIO::UDSEntry::UDS_CREATION_TIME, 12345); + entry.fastInsert(KIO::UDSEntry::UDS_DEVICE_ID, 2); + entry.fastInsert(KIO::UDSEntry::UDS_INODE, 56); + + // Same as entry + KIO::UDSEntry entry2; + entry2.fastInsert(KIO::UDSEntry::UDS_SIZE, 1); + entry2.fastInsert(KIO::UDSEntry::UDS_USER, QStringLiteral("user1")); + entry2.fastInsert(KIO::UDSEntry::UDS_GROUP, QStringLiteral("group1")); + entry2.fastInsert(KIO::UDSEntry::UDS_NAME, QStringLiteral("filename1")); + entry2.fastInsert(KIO::UDSEntry::UDS_MODIFICATION_TIME, 123456); + entry2.fastInsert(KIO::UDSEntry::UDS_CREATION_TIME, 12345); + entry2.fastInsert(KIO::UDSEntry::UDS_DEVICE_ID, 2); + entry2.fastInsert(KIO::UDSEntry::UDS_INODE, 56); + + // 3nd entry: different user. + KIO::UDSEntry entry3; + entry3.fastInsert(KIO::UDSEntry::UDS_SIZE, 1); + entry3.fastInsert(KIO::UDSEntry::UDS_USER, QStringLiteral("other user")); + entry3.fastInsert(KIO::UDSEntry::UDS_GROUP, QStringLiteral("group1")); + entry3.fastInsert(KIO::UDSEntry::UDS_NAME, QStringLiteral("filename1")); + entry3.fastInsert(KIO::UDSEntry::UDS_MODIFICATION_TIME, 123456); + entry3.fastInsert(KIO::UDSEntry::UDS_CREATION_TIME, 12345); + entry3.fastInsert(KIO::UDSEntry::UDS_DEVICE_ID, 2); + entry3.fastInsert(KIO::UDSEntry::UDS_INODE, 56); + + // 4th entry : an additional field + KIO::UDSEntry entry4; + entry4.fastInsert(KIO::UDSEntry::UDS_SIZE, 1); + entry4.fastInsert(KIO::UDSEntry::UDS_USER, QStringLiteral("user1")); + entry4.fastInsert(KIO::UDSEntry::UDS_GROUP, QStringLiteral("group1")); + entry4.fastInsert(KIO::UDSEntry::UDS_NAME, QStringLiteral("filename1")); + entry4.fastInsert(KIO::UDSEntry::UDS_ICON_NAME, QStringLiteral("home")); + entry4.fastInsert(KIO::UDSEntry::UDS_MODIFICATION_TIME, 123456); + entry4.fastInsert(KIO::UDSEntry::UDS_CREATION_TIME, 12345); + entry4.fastInsert(KIO::UDSEntry::UDS_DEVICE_ID, 2); + entry4.fastInsert(KIO::UDSEntry::UDS_INODE, 56); + + // == + QVERIFY(entry == entry2); + QVERIFY(!(entry == entry3)); + QVERIFY(!(entry == entry4)); + QVERIFY(!(entry2 == entry3)); + + // != + QVERIFY(!(entry != entry2)); + QVERIFY(entry != entry3); + QVERIFY(entry != entry4); + QVERIFY(entry2 != entry3); + + // make entry3 == entry + entry3.replace(KIO::UDSEntry::UDS_USER, QStringLiteral("user1")); + + QVERIFY(entry == entry3); + QVERIFY(entry2 == entry3); + QVERIFY(!(entry != entry3)); + QVERIFY(!(entry2 != entry3)); +} + QTEST_MAIN(UDSEntryTest) diff --git a/autotests/udsentrytest.h b/autotests/udsentrytest.h index 3e41c9e6..2bf311f4 100644 --- a/autotests/udsentrytest.h +++ b/autotests/udsentrytest.h @@ -1,34 +1,35 @@ /* This file is part of the KDE project Copyright (C) 2013 Frank Reininghaus This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef UDSENTRYTEST_H #define UDSENTRYTEST_H #include class UDSEntryTest : public QObject { Q_OBJECT private Q_SLOTS: void testSaveLoad(); void testMove(); + void testEquality(); }; #endif diff --git a/src/core/udsentry.cpp b/src/core/udsentry.cpp index f5573c38..ba50559c 100644 --- a/src/core/udsentry.cpp +++ b/src/core/udsentry.cpp @@ -1,465 +1,496 @@ /* This file is part of the KDE project Copyright (C) 2000-2005 David Faure Copyright (C) 2007 Norbert Frese Copyright (C) 2007 Thiago Macieira Copyright (C) 2013-2014 Frank Reininghaus This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "udsentry.h" #include #include #include #include #include #include using namespace KIO; //BEGIN UDSEntryPrivate /* ---------- UDSEntryPrivate ------------ */ class KIO::UDSEntryPrivate : public QSharedData { public: void reserve(int size); void insert(uint udsField, const QString &value); void replace(uint udsField, const QString &value); void insert(uint udsField, long long value); void replace(uint udsField, long long value); int count() const; QString stringValue(uint udsField) const; long long numberValue(uint udsField, long long defaultValue = -1) const; #ifndef KIOCORE_NO_DEPRECATED QList listFields() const; #endif QVector fields() const; bool contains(uint udsField) const; void clear(); void save(QDataStream &s) const; void load(QDataStream &s); void debugUDSEntry(QDebug &stream) const; /** * @param field numeric UDS field id * @return the name of the field */ static QString nameOfUdsField(uint field); private: struct Field { inline Field() {} inline Field(const uint index, const QString &value) : m_str(value), m_index(index) {} inline Field(const uint index, long long value = 0) : m_long(value), m_index(index) {} QString m_str; long long m_long = LLONG_MIN; uint m_index = 0; }; std::vector storage; }; void UDSEntryPrivate::reserve(int size) { storage.reserve(size); } void UDSEntryPrivate::insert(uint udsField, const QString &value) { Q_ASSERT(udsField & KIO::UDSEntry::UDS_STRING); Q_ASSERT(std::find_if(storage.cbegin(), storage.cend(), [udsField](const Field &entry) {return entry.m_index == udsField;}) == storage.cend()); storage.emplace_back(udsField, value); } void UDSEntryPrivate::replace(uint udsField, const QString &value) { Q_ASSERT(udsField & KIO::UDSEntry::UDS_STRING); auto it = std::find_if(storage.begin(), storage.end(), [udsField](const Field &entry) {return entry.m_index == udsField;}); if (it != storage.end()) { it->m_str = value; return; } storage.emplace_back(udsField, value); } void UDSEntryPrivate::insert(uint udsField, long long value) { Q_ASSERT(udsField & KIO::UDSEntry::UDS_NUMBER); Q_ASSERT(std::find_if(storage.cbegin(), storage.cend(), [udsField](const Field &entry) {return entry.m_index == udsField;}) == storage.cend()); storage.emplace_back(udsField, value); } void UDSEntryPrivate::replace(uint udsField, long long value) { Q_ASSERT(udsField & KIO::UDSEntry::UDS_NUMBER); auto it = std::find_if(storage.begin(), storage.end(), [udsField](const Field &entry) {return entry.m_index == udsField;}); if (it != storage.end()) { it->m_long = value; return; } storage.emplace_back(udsField, value); } int UDSEntryPrivate::count() const { return storage.size(); } QString UDSEntryPrivate::stringValue(uint udsField) const { auto it = std::find_if(storage.cbegin(), storage.cend(), [udsField](const Field &entry) {return entry.m_index == udsField;}); if (it != storage.cend()) { return it->m_str; } return QString(); } long long UDSEntryPrivate::numberValue(uint udsField, long long defaultValue) const { auto it = std::find_if(storage.cbegin(), storage.cend(), [udsField](const Field &entry) {return entry.m_index == udsField;}); if (it != storage.cend()) { return it->m_long; } return defaultValue; } #ifndef KIOCORE_NO_DEPRECATED QList UDSEntryPrivate::listFields() const { QList res; res.reserve(storage.size()); for (auto it = storage.cbegin(), end = storage.cend(); it != end; ++it) { res.append(it->m_index); } return res; } #endif QVector UDSEntryPrivate::fields() const { QVector res; res.reserve(storage.size()); for (auto it = storage.cbegin(), end = storage.cend(); it != end; ++it) { res.append(it->m_index); } return res; } bool UDSEntryPrivate::contains(uint udsField) const { auto it = std::find_if(storage.cbegin(), storage.cend(), [udsField](const Field &entry) {return entry.m_index == udsField;}); return (it != storage.cend()); } void UDSEntryPrivate::clear() { storage.clear(); } void UDSEntryPrivate::save(QDataStream &s) const { s << static_cast(storage.size()); for (auto it = storage.cbegin(), end = storage.cend(); it != end; ++it) { uint uds = it->m_index; s << uds; if (uds & KIO::UDSEntry::UDS_STRING) { s << it->m_str; } else if (uds & KIO::UDSEntry::UDS_NUMBER) { s << it->m_long; } else { Q_ASSERT_X(false, "KIO::UDSEntry", "Found a field with an invalid type"); } } } void UDSEntryPrivate::load(QDataStream &s) { clear(); quint32 size; s >> size; reserve(size); // We cache the loaded strings. Some of them, like, e.g., the user, // will often be the same for many entries in a row. Caching them // permits to use implicit sharing to save memory. static QVector cachedStrings; if (quint32(cachedStrings.size()) < size) { cachedStrings.resize(size); } for (quint32 i = 0; i < size; ++i) { quint32 uds; s >> uds; if (uds & KIO::UDSEntry::UDS_STRING) { // If the QString is the same like the one we read for the // previous UDSEntry at the i-th position, use an implicitly // shared copy of the same QString to save memory. QString buffer; s >> buffer; if (buffer != cachedStrings.at(i)) { cachedStrings[i] = buffer; } insert(uds, cachedStrings.at(i)); } else if (uds & KIO::UDSEntry::UDS_NUMBER) { long long value; s >> value; insert(uds, value); } else { Q_ASSERT_X(false, "KIO::UDSEntry", "Found a field with an invalid type"); } } } QString UDSEntryPrivate::nameOfUdsField(uint field) { switch (field) { case UDSEntry::UDS_SIZE: return QStringLiteral("UDS_SIZE"); case UDSEntry::UDS_SIZE_LARGE: return QStringLiteral("UDS_SIZE_LARGE"); case UDSEntry::UDS_USER: return QStringLiteral("UDS_USER"); case UDSEntry::UDS_ICON_NAME: return QStringLiteral("UDS_ICON_NAME"); case UDSEntry::UDS_GROUP: return QStringLiteral("UDS_GROUP"); case UDSEntry::UDS_NAME: return QStringLiteral("UDS_NAME"); case UDSEntry::UDS_LOCAL_PATH: return QStringLiteral("UDS_LOCAL_PATH"); case UDSEntry::UDS_HIDDEN: return QStringLiteral("UDS_HIDDEN"); case UDSEntry::UDS_ACCESS: return QStringLiteral("UDS_ACCESS"); case UDSEntry::UDS_MODIFICATION_TIME: return QStringLiteral("UDS_MODIFICATION_TIME"); case UDSEntry::UDS_ACCESS_TIME: return QStringLiteral("UDS_ACCESS_TIME"); case UDSEntry::UDS_CREATION_TIME: return QStringLiteral("UDS_CREATION_TIME"); case UDSEntry::UDS_FILE_TYPE: return QStringLiteral("UDS_FILE_TYPE"); case UDSEntry::UDS_LINK_DEST: return QStringLiteral("UDS_LINK_DEST"); case UDSEntry::UDS_URL: return QStringLiteral("UDS_URL"); case UDSEntry::UDS_MIME_TYPE: return QStringLiteral("UDS_MIME_TYPE"); case UDSEntry::UDS_GUESSED_MIME_TYPE: return QStringLiteral("UDS_GUESSED_MIME_TYPE"); case UDSEntry::UDS_XML_PROPERTIES: return QStringLiteral("UDS_XML_PROPERTIES"); case UDSEntry::UDS_EXTENDED_ACL: return QStringLiteral("UDS_EXTENDED_ACL"); case UDSEntry::UDS_ACL_STRING: return QStringLiteral("UDS_ACL_STRING"); case UDSEntry::UDS_DEFAULT_ACL_STRING: return QStringLiteral("UDS_DEFAULT_ACL_STRING"); case UDSEntry::UDS_DISPLAY_NAME: return QStringLiteral("UDS_DISPLAY_NAME"); case UDSEntry::UDS_TARGET_URL: return QStringLiteral("UDS_TARGET_URL"); case UDSEntry::UDS_DISPLAY_TYPE: return QStringLiteral("UDS_DISPLAY_TYPE"); case UDSEntry::UDS_ICON_OVERLAY_NAMES: return QStringLiteral("UDS_ICON_OVERLAY_NAMES"); case UDSEntry::UDS_COMMENT: return QStringLiteral("UDS_COMMENT"); case UDSEntry::UDS_DEVICE_ID: return QStringLiteral("UDS_DEVICE_ID"); case UDSEntry::UDS_INODE: return QStringLiteral("UDS_INODE"); case UDSEntry::UDS_EXTRA: return QStringLiteral("UDS_EXTRA"); case UDSEntry::UDS_EXTRA_END: return QStringLiteral("UDS_EXTRA_END"); default: return QStringLiteral("Unknown uds field %1").arg(field); } } void UDSEntryPrivate::debugUDSEntry(QDebug &stream) const { QDebugStateSaver saver(stream); stream.nospace() << "["; for (auto it = storage.cbegin(), end = storage.cend(); it != end; ++it) { stream << " " << nameOfUdsField(it->m_index) << "="; if (it->m_index & KIO::UDSEntry::UDS_STRING) { stream << it->m_str; } else if (it->m_index & KIO::UDSEntry::UDS_NUMBER) { stream << it->m_long; } else { Q_ASSERT_X(false, "KIO::UDSEntry", "Found a field with an invalid type"); } } stream << " ]"; } //END UDSEntryPrivate //BEGIN UDSEntry /* ---------- UDSEntry ------------ */ UDSEntry::UDSEntry() : d(new UDSEntryPrivate()) { } // BUG: this API doesn't allow to handle symlinks correctly (we need buff from QT_LSTAT for most things, but buff from QT_STAT for st_mode and st_size) UDSEntry::UDSEntry(const QT_STATBUF &buff, const QString &name) : d(new UDSEntryPrivate()) { #ifndef Q_OS_WIN d->reserve(10); #else d->reserve(8); #endif d->insert(UDS_NAME, name); d->insert(UDS_SIZE, buff.st_size); d->insert(UDS_DEVICE_ID, buff.st_dev); d->insert(UDS_INODE, buff.st_ino); d->insert(UDS_FILE_TYPE, buff.st_mode & QT_STAT_MASK); // extract file type d->insert(UDS_ACCESS, buff.st_mode & 07777); // extract permissions d->insert(UDS_MODIFICATION_TIME, buff.st_mtime); d->insert(UDS_ACCESS_TIME, buff.st_atime); #ifndef Q_OS_WIN d->insert(UDS_USER, KUser(buff.st_uid).loginName()); d->insert(UDS_GROUP, KUserGroup(buff.st_gid).name()); #endif } UDSEntry::UDSEntry(const UDSEntry&) = default; UDSEntry::~UDSEntry() = default; UDSEntry::UDSEntry(UDSEntry&&) = default; UDSEntry& UDSEntry::operator=(const UDSEntry&) = default; UDSEntry& UDSEntry::operator=(UDSEntry&&) = default; QString UDSEntry::stringValue(uint field) const { return d->stringValue(field); } long long UDSEntry::numberValue(uint field, long long defaultValue) const { return d->numberValue(field, defaultValue); } bool UDSEntry::isDir() const { return (numberValue(UDS_FILE_TYPE) & QT_STAT_MASK) == QT_STAT_DIR; } bool UDSEntry::isLink() const { return !stringValue(UDS_LINK_DEST).isEmpty(); } void UDSEntry::reserve(int size) { d->reserve(size); } void UDSEntry::fastInsert(uint field, const QString &value) { d->insert(field, value); } void UDSEntry::fastInsert(uint field, long long value) { d->insert(field, value); } void UDSEntry::insert(uint field, const QString &value) { d->replace(field, value); } void UDSEntry::insert(uint field, long long value) { d->replace(field, value); } void UDSEntry::replace(uint field, const QString &value) { d->replace(field, value); } void UDSEntry::replace(uint field, long long value) { d->replace(field, value); } #ifndef KIOCORE_NO_DEPRECATED QList UDSEntry::listFields() const { return d->listFields(); } #endif QVector UDSEntry::fields() const { return d->fields(); } int UDSEntry::count() const { return d->count(); } bool UDSEntry::contains(uint field) const { return d->contains(field); } void UDSEntry::clear() { d->clear(); } //END UDSEntry KIOCORE_EXPORT QDebug operator<<(QDebug stream, const KIO::UDSEntry &entry) { entry.d->debugUDSEntry(stream); return stream; } KIOCORE_EXPORT QDataStream &operator<<(QDataStream &s, const KIO::UDSEntry &a) { a.d->save(s); return s; } KIOCORE_EXPORT QDataStream &operator>>(QDataStream &s, KIO::UDSEntry &a) { a.d->load(s); return s; } + +KIOCORE_EXPORT bool operator==(const KIO::UDSEntry &entry, const KIO::UDSEntry &other) +{ + if (entry.count() != other.count()) { + return false; + } + + const QVector fields = entry.fields(); + for (uint field : fields) { + if (!other.contains(field)) { + return false; + } + + if (field & UDSEntry::UDS_STRING) { + if (entry.stringValue(field) != other.stringValue(field)) { + return false; + } + } else { + if (entry.numberValue(field) != other.numberValue(field)) { + return false; + } + } + } + + return true; +} + +KIOCORE_EXPORT bool operator!=(const KIO::UDSEntry &entry, const KIO::UDSEntry &other) +{ + return !(entry == other); +} diff --git a/src/core/udsentry.h b/src/core/udsentry.h index 503c1552..50f34e03 100644 --- a/src/core/udsentry.h +++ b/src/core/udsentry.h @@ -1,386 +1,399 @@ /* This file is part of the KDE libraries Copyright (C) 2000-2005 David Faure Copyright (C) 2007 Norbert Frese Copyright (C) 2007 Thiago Macieira This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef UDSENTRY_H #define UDSENTRY_H #include #include #include #include #include #include #include "kiocore_export.h" namespace KIO { class UDSEntry; } KIOCORE_EXPORT QDataStream &operator<< (QDataStream &s, const KIO::UDSEntry &a); KIOCORE_EXPORT QDataStream &operator>> (QDataStream &s, KIO::UDSEntry &a); /** * Support for qDebug() << aUDSEntry * \since 5.22 */ KIOCORE_EXPORT QDebug operator<<(QDebug stream, const KIO::UDSEntry &entry); +/** + * Returns true if the entry contains the same data as the other + * @since 5.63 + */ +KIOCORE_EXPORT bool operator== (const KIO::UDSEntry &entry, const KIO::UDSEntry &other); + +/** + * Returns true if the entry does not contain the same data as the other + * @since 5.63 + */ +KIOCORE_EXPORT bool operator!= (const KIO::UDSEntry &entry, const KIO::UDSEntry &other); + namespace KIO { class UDSEntryPrivate; /** * @class KIO::UDSEntry udsentry.h * * Universal Directory Service * * UDS entry is the data structure representing all the fields about a given URL * (file or directory). * * The KIO::listDir() and KIO:stat() operations use this data structure. * * KIO defines a number of standard fields, see the UDS_XXX enums (see StandardFieldTypes). * at the moment UDSEntry only provides fields with numeric indexes, * but there might be named fields with string indexes in the future. * * For instance, to retrieve the name of the entry, use: * \code * QString displayName = entry.stringValue( KIO::UDSEntry::UDS_NAME ); * \endcode * * To know the modification time of the file/url: * \code * QDateTime mtime = QDateTime::fromSecsSinceEpoch(entry.numberValue(KIO::UDSEntry::UDS_MODIFICATION_TIME, 0)); * if (mtime.isValid()) * ... * \endcode */ class KIOCORE_EXPORT UDSEntry { public: UDSEntry(); /** * Create a UDSEntry by QT_STATBUF * @param buff QT_STATBUFF object * @param name filename * @since 5.0 */ UDSEntry(const QT_STATBUF &buff, const QString &name = QString()); /** * Copy constructor */ UDSEntry(const UDSEntry&); /** * Destructor */ ~UDSEntry(); /** * Move constructor * @since 5.44 */ UDSEntry(UDSEntry&&); /** * Copy assignment */ UDSEntry& operator=(const UDSEntry&); /** * Move assignment * @since 5.44 */ UDSEntry& operator=(UDSEntry&&); /** * @return value of a textual field */ QString stringValue(uint field) const; /** * @return value of a numeric field */ long long numberValue(uint field, long long defaultValue = 0) const; // Convenience methods. // Let's not add one method per field, only methods that have some more logic // than just calling stringValue(field) or numberValue(field). /// @return true if this entry is a directory (or a link to a directory) bool isDir() const; /// @return true if this entry is a link bool isLink() const; /** * Calling this function before inserting items into an empty UDSEntry may save time and memory. * @param size number of items for which memory will be pre-allocated */ void reserve(int size); /** * insert field with string value * @param field numeric field id * @param value to set * @deprecated since 5.48 in favor of fastInsert or replace */ KIOCORE_DEPRECATED void insert(uint field, const QString &value); /** * insert field with numeric value * @param field numeric field id * @param l value to set * @deprecated since 5.48 in favor of fastInsert or replace */ KIOCORE_DEPRECATED void insert(uint field, long long l); /** * insert field with string value, it will assert if the field is already inserted. In that case, use replace() instead. * @param field numeric field id * @param value to set * @since 5.48 */ void fastInsert(uint field, const QString &value); /** * insert field with numeric value, it will assert if the field is already inserted. In that case, use replace() instead. * @param field numeric field id * @param l value to set * @since 5.48 */ void fastInsert(uint field, long long l); /** * count fields * @return the number of fields */ int count() const; /** * check existence of a field * @param field numeric field id */ bool contains(uint field) const; /** * List all fields. * @return all fields. * @deprecated since 5.8. Use fields() instead. */ #ifndef KIOCORE_NO_DEPRECATED KIOCORE_DEPRECATED QList listFields() const; #endif /** * A vector of fields being present for the current entry. * @return all fields for the current entry. * @since 5.8 */ QVector fields() const; /** * remove all fields */ void clear(); /** * Constants used to specify the type of a UDSField. */ enum StandardFieldTypes { // First let's define the item types: bit field /// Indicates that the field is a QString UDS_STRING = 0x01000000, /// Indicates that the field is a number (long long) UDS_NUMBER = 0x02000000, /// Indicates that the field represents a time, which is modelled by a long long UDS_TIME = 0x04000000 | UDS_NUMBER, // The rest isn't a bit field /// Size of the file UDS_SIZE = 1 | UDS_NUMBER, /// @internal UDS_SIZE_LARGE = 2 | UDS_NUMBER, /// User ID of the file owner UDS_USER = 3 | UDS_STRING, /// Name of the icon, that should be used for displaying. /// It overrides all other detection mechanisms UDS_ICON_NAME = 4 | UDS_STRING, /// Group ID of the file owner UDS_GROUP = 5 | UDS_STRING, /// Filename - as displayed in directory listings etc. /// "." has the usual special meaning of "current directory" /// UDS_NAME must always be set and never be empty, neither contain '/'. /// /// Note that KIO will append the UDS_NAME to the url of their /// parent directory, so all kioslaves must use that naming scheme /// ("url_of_parent/filename" will be the full url of that file). /// To customize the appearance of files without changing the url /// of the items, use UDS_DISPLAY_NAME. UDS_NAME = 6 | UDS_STRING, /// A local file path if the ioslave display files sitting /// on the local filesystem (but in another hierarchy, e.g. settings:/ or remote:/) UDS_LOCAL_PATH = 7 | UDS_STRING, /// Treat the file as a hidden file (if set to 1) or as a normal file (if set to 0). /// This field overrides the default behavior (the check for a leading dot in the filename). UDS_HIDDEN = 8 | UDS_NUMBER, /// Access permissions (part of the mode returned by stat) UDS_ACCESS = 9 | UDS_NUMBER, /// The last time the file was modified UDS_MODIFICATION_TIME = 10 | UDS_TIME, /// The last time the file was opened UDS_ACCESS_TIME = 11 | UDS_TIME, /// The time the file was created UDS_CREATION_TIME = 12 | UDS_TIME, /// File type, part of the mode returned by stat /// (for a link, this returns the file type of the pointed item) /// check UDS_LINK_DEST to know if this is a link UDS_FILE_TYPE = 13 | UDS_NUMBER, /// Name of the file where the link points to /// Allows to check for a symlink (don't use S_ISLNK !) UDS_LINK_DEST = 14 | UDS_STRING, /// An alternative URL (If different from the caption). /// Can be used to mix different hierarchies. /// /// Use UDS_DISPLAY_NAME if you simply want to customize the user-visible filenames, or use /// UDS_TARGET_URL if you want "links" to unrelated urls. UDS_URL = 15 | UDS_STRING, /// A mime type; the slave should set it if it's known. UDS_MIME_TYPE = 16 | UDS_STRING, /// A mime type to be used for displaying only. /// But when 'running' the file, the mimetype is re-determined /// This is for special cases like symlinks in FTP; you probably don't want to use this one. UDS_GUESSED_MIME_TYPE = 17 | UDS_STRING, /// XML properties, e.g. for WebDAV UDS_XML_PROPERTIES = 18 | UDS_STRING, /// Indicates that the entry has extended ACL entries UDS_EXTENDED_ACL = 19 | UDS_NUMBER, /// The access control list serialized into a single string. UDS_ACL_STRING = 20 | UDS_STRING, /// The default access control list serialized into a single string. /// Only available for directories. UDS_DEFAULT_ACL_STRING = 21 | UDS_STRING, /// If set, contains the label to display instead of /// the 'real name' in UDS_NAME /// @since 4.1 UDS_DISPLAY_NAME = 22 | UDS_STRING, /// This file is a shortcut or mount, pointing to an /// URL in a different hierarchy /// @since 4.1 UDS_TARGET_URL = 23 | UDS_STRING, /// User-readable type of file (if not specified, /// the mimetype's description is used) /// @since 4.4 UDS_DISPLAY_TYPE = 24 | UDS_STRING, /// 25 was used by the now removed UDS_NEPOMUK_URI /// A comma-separated list of supplementary icon overlays /// which will be added to the list of overlays created /// by KFileItem. /// /// @since 4.5 UDS_ICON_OVERLAY_NAMES = 26 | UDS_STRING, /// 27 was used by the now removed UDS_NEPOMUK_QUERY /// A comment which will be displayed as is to the user. The string /// value may contain plain text or Qt-style rich-text extensions. /// /// @since 4.6 UDS_COMMENT = 28 | UDS_STRING, /// Device number for this file, used to detect hardlinks /// @since 4.7.3 UDS_DEVICE_ID = 29 | UDS_NUMBER, /// Inode number for this file, used to detect hardlinks /// @since 4.7.3 UDS_INODE = 30 | UDS_NUMBER, /// Extra data (used only if you specified Columns/ColumnsTypes) /// NB: you cannot repeat this entry; use UDS_EXTRA + i /// until UDS_EXTRA_END. UDS_EXTRA = 100 | UDS_STRING, /// Extra data (used only if you specified Columns/ColumnsTypes) /// NB: you cannot repeat this entry; use UDS_EXTRA + i /// until UDS_EXTRA_END. UDS_EXTRA_END = 140 | UDS_STRING }; private: QSharedDataPointer d; friend KIOCORE_EXPORT QDataStream& ::operator<< (QDataStream &s, const KIO::UDSEntry &a); friend KIOCORE_EXPORT QDataStream& ::operator>> (QDataStream &s, KIO::UDSEntry &a); friend KIOCORE_EXPORT QDebug (::operator<<) (QDebug stream, const KIO::UDSEntry &entry); + public: /** * Replace or insert field with string value * @param field numeric field id * @param value to set * @since 5.47 */ void replace(uint field, const QString &value); /** * Replace or insert field with numeric value * @param field numeric field id * @param l value to set * @since 5.47 */ void replace(uint field, long long l); }; } Q_DECLARE_TYPEINFO(KIO::UDSEntry, Q_MOVABLE_TYPE); namespace KIO { /** * A directory listing is a list of UDSEntry instances. * * To list the name and size of all the files in a directory listing you would do: * \code * KIO::UDSEntryList::ConstIterator it = entries.begin(); * const KIO::UDSEntryList::ConstIterator end = entries.end(); * for (; it != end; ++it) { * const KIO::UDSEntry& entry = *it; * QString name = entry.stringValue( KIO::UDSEntry::UDS_NAME ); * bool isDir = entry.isDir(); * KIO::filesize_t size = entry.numberValue( KIO::UDSEntry::UDS_SIZE, -1 ); * ... * } * \endcode */ typedef QList UDSEntryList; } // end namespace Q_DECLARE_METATYPE(KIO::UDSEntry) #endif /*UDSENTRY_H*/ diff --git a/tests/udsentrybenchmark.cpp b/tests/udsentrybenchmark.cpp index feb104d8..e376e984 100644 --- a/tests/udsentrybenchmark.cpp +++ b/tests/udsentrybenchmark.cpp @@ -1,330 +1,303 @@ /*************************************************************************** * Copyright (C) 2014 by Frank Reininghaus * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * ***************************************************************************/ #include #include /** * This benchmarks tests four typical uses of UDSEntry: * * (a) Store data in UDSEntries using * UDSEntry::insert(uint, const QString&) and * UDSEntry::insert(uint, long long), * and append the entries to a UDSEntryList. * * (b) Read data from UDSEntries in a UDSEntryList using * UDSEntry::stringValue(uint) and UDSEntry::numberValue(uint). * * (c) Save a UDSEntryList in a QDataStream. * * (d) Load a UDSEntryList from a QDataStream. * * This is done for two different data sets: * * 1. UDSEntries containing the entries which are provided by kio_file. * * 2. UDSEntries with a larger number of "fields". */ // The following constants control the number of UDSEntries that are considered // in each test, and the number of extra "fields" that are used for large UDSEntries. const int numberOfSmallUDSEntries = 100 * 1000; const int numberOfLargeUDSEntries = 5 * 1000; const int extraFieldsForLargeUDSEntries = 40; class UDSEntryBenchmark : public QObject { Q_OBJECT public: UDSEntryBenchmark(); private Q_SLOTS: void createSmallEntries(); void createLargeEntries(); void readFieldsFromSmallEntries(); void readFieldsFromLargeEntries(); void saveSmallEntries(); void saveLargeEntries(); void loadSmallEntries(); void loadLargeEntries(); private: KIO::UDSEntryList m_smallEntries; KIO::UDSEntryList m_largeEntries; QByteArray m_savedSmallEntries; QByteArray m_savedLargeEntries; QVector m_fieldsForLargeEntries; }; UDSEntryBenchmark::UDSEntryBenchmark() { m_fieldsForLargeEntries.append(KIO::UDSEntry::UDS_SIZE); m_fieldsForLargeEntries.append(KIO::UDSEntry::UDS_SIZE_LARGE); m_fieldsForLargeEntries.append(KIO::UDSEntry::UDS_USER); m_fieldsForLargeEntries.append(KIO::UDSEntry::UDS_ICON_NAME); m_fieldsForLargeEntries.append(KIO::UDSEntry::UDS_GROUP); m_fieldsForLargeEntries.append(KIO::UDSEntry::UDS_NAME); m_fieldsForLargeEntries.append(KIO::UDSEntry::UDS_LOCAL_PATH); m_fieldsForLargeEntries.append(KIO::UDSEntry::UDS_HIDDEN); m_fieldsForLargeEntries.append(KIO::UDSEntry::UDS_ACCESS); m_fieldsForLargeEntries.append(KIO::UDSEntry::UDS_MODIFICATION_TIME); m_fieldsForLargeEntries.append(KIO::UDSEntry::UDS_ACCESS_TIME); m_fieldsForLargeEntries.append(KIO::UDSEntry::UDS_CREATION_TIME); m_fieldsForLargeEntries.append(KIO::UDSEntry::UDS_FILE_TYPE); m_fieldsForLargeEntries.append(KIO::UDSEntry::UDS_LINK_DEST); m_fieldsForLargeEntries.append(KIO::UDSEntry::UDS_URL); m_fieldsForLargeEntries.append(KIO::UDSEntry::UDS_MIME_TYPE); m_fieldsForLargeEntries.append(KIO::UDSEntry::UDS_GUESSED_MIME_TYPE); m_fieldsForLargeEntries.append(KIO::UDSEntry::UDS_XML_PROPERTIES); m_fieldsForLargeEntries.append(KIO::UDSEntry::UDS_EXTENDED_ACL); m_fieldsForLargeEntries.append(KIO::UDSEntry::UDS_ACL_STRING); m_fieldsForLargeEntries.append(KIO::UDSEntry::UDS_DEFAULT_ACL_STRING); m_fieldsForLargeEntries.append(KIO::UDSEntry::UDS_DISPLAY_NAME); m_fieldsForLargeEntries.append(KIO::UDSEntry::UDS_TARGET_URL); m_fieldsForLargeEntries.append(KIO::UDSEntry::UDS_DISPLAY_TYPE); m_fieldsForLargeEntries.append(KIO::UDSEntry::UDS_ICON_OVERLAY_NAMES); m_fieldsForLargeEntries.append(KIO::UDSEntry::UDS_COMMENT); m_fieldsForLargeEntries.append(KIO::UDSEntry::UDS_DEVICE_ID); m_fieldsForLargeEntries.append(KIO::UDSEntry::UDS_INODE); for (int i = 0; i < extraFieldsForLargeUDSEntries; ++i) { m_fieldsForLargeEntries.append(KIO::UDSEntry::UDS_EXTRA + i); } } void UDSEntryBenchmark::createSmallEntries() { m_smallEntries.clear(); m_smallEntries.reserve(numberOfSmallUDSEntries); const QString user = QStringLiteral("user"); const QString group = QStringLiteral("group"); QVector names(numberOfSmallUDSEntries); for (int i = 0; i < numberOfSmallUDSEntries; ++i) { names[i] = QString::number(i); } QBENCHMARK_ONCE { for (int i = 0; i < numberOfSmallUDSEntries; ++i) { KIO::UDSEntry entry; entry.reserve(8); entry.fastInsert(KIO::UDSEntry::UDS_NAME, names[i]); entry.fastInsert(KIO::UDSEntry::UDS_FILE_TYPE, i); entry.fastInsert(KIO::UDSEntry::UDS_ACCESS, i); entry.fastInsert(KIO::UDSEntry::UDS_SIZE, i); entry.fastInsert(KIO::UDSEntry::UDS_MODIFICATION_TIME, i); entry.fastInsert(KIO::UDSEntry::UDS_USER, user); entry.fastInsert(KIO::UDSEntry::UDS_GROUP, group); entry.fastInsert(KIO::UDSEntry::UDS_ACCESS_TIME, i); m_smallEntries.append(entry); } } Q_ASSERT(m_smallEntries.count() == numberOfSmallUDSEntries); } void UDSEntryBenchmark::createLargeEntries() { m_largeEntries.clear(); m_largeEntries.reserve(numberOfLargeUDSEntries); QVector names(numberOfLargeUDSEntries); for (int i = 0; i < numberOfLargeUDSEntries; ++i) { names[i] = QString::number(i); } QBENCHMARK_ONCE { for (int i = 0; i < numberOfLargeUDSEntries; ++i) { KIO::UDSEntry entry; entry.reserve(m_fieldsForLargeEntries.count()); foreach (uint field, m_fieldsForLargeEntries) { if (field & KIO::UDSEntry::UDS_STRING) { entry.fastInsert(field, names[i]); } else { entry.fastInsert(field, i); } } m_largeEntries.append(entry); } } Q_ASSERT(m_largeEntries.count() == numberOfLargeUDSEntries); } void UDSEntryBenchmark::readFieldsFromSmallEntries() { // Create the entries if they do not exist yet. if (m_smallEntries.isEmpty()) { createSmallEntries(); } const QString user = QStringLiteral("user"); const QString group = QStringLiteral("group"); QBENCHMARK { long long i = 0; long long entrySum = 0; foreach (const KIO::UDSEntry& entry, m_smallEntries) { entrySum += entry.count(); if (entry.stringValue(KIO::UDSEntry::UDS_NAME).toInt() == i && entry.numberValue(KIO::UDSEntry::UDS_FILE_TYPE) == i && entry.numberValue(KIO::UDSEntry::UDS_ACCESS) == i && entry.numberValue(KIO::UDSEntry::UDS_SIZE) == i && entry.numberValue(KIO::UDSEntry::UDS_MODIFICATION_TIME) == i && entry.stringValue(KIO::UDSEntry::UDS_USER) == user && entry.stringValue(KIO::UDSEntry::UDS_GROUP) == group && entry.numberValue(KIO::UDSEntry::UDS_ACCESS_TIME) == i) { ++i; } } QCOMPARE(i, numberOfSmallUDSEntries); QCOMPARE(entrySum, numberOfSmallUDSEntries * 8); } } void UDSEntryBenchmark::readFieldsFromLargeEntries() { // Create the entries if they do not exist yet. if (m_largeEntries.isEmpty()) { createLargeEntries(); } QBENCHMARK_ONCE { long long i = 0; long long fieldSum = 0; foreach (const KIO::UDSEntry& entry, m_largeEntries) { foreach (uint field, m_fieldsForLargeEntries) { if (field & KIO::UDSEntry::UDS_STRING) { if (entry.stringValue(field).toInt() == i) { ++fieldSum; } } else if (entry.numberValue(field) == i) { ++fieldSum; } } ++i; } QCOMPARE(fieldSum, m_fieldsForLargeEntries.count() * m_largeEntries.count()); } } void UDSEntryBenchmark::saveSmallEntries() { // Create the entries if they do not exist yet. if (m_smallEntries.isEmpty()) { createSmallEntries(); } m_savedSmallEntries.clear(); QBENCHMARK_ONCE { QDataStream stream(&m_savedSmallEntries, QIODevice::WriteOnly); stream << m_smallEntries; } } void UDSEntryBenchmark::saveLargeEntries() { // Create the entries if they do not exist yet. if (m_smallEntries.isEmpty()) { createLargeEntries(); } m_savedLargeEntries.clear(); QBENCHMARK_ONCE { QDataStream stream(&m_savedLargeEntries, QIODevice::WriteOnly); stream << m_largeEntries; } } -namespace KIO { -static bool operator==(const UDSEntry &a, const UDSEntry &b) -{ - if (a.count() != b.count()) { - return false; - } - - const QVector fields = a.fields(); - for (uint field : fields) { - if (!b.contains(field)) { - return false; - } - - if (field & UDSEntry::UDS_STRING) { - if (a.stringValue(field) != b.stringValue(field)) { - return false; - } - } else { - if (a.numberValue(field) != b.numberValue(field)) { - return false; - } - } - } - - return true; -} -} void UDSEntryBenchmark::loadSmallEntries() { // Save the entries if that has not been done yet. if (m_savedSmallEntries.isEmpty()) { saveSmallEntries(); } QDataStream stream(m_savedSmallEntries); KIO::UDSEntryList entries; QBENCHMARK_ONCE { stream >> entries; } QCOMPARE(entries, m_smallEntries); } void UDSEntryBenchmark::loadLargeEntries() { // Save the entries if that has not been done yet. if (m_savedLargeEntries.isEmpty()) { saveLargeEntries(); } QDataStream stream(m_savedLargeEntries); KIO::UDSEntryList entries; QBENCHMARK_ONCE { stream >> entries; } QCOMPARE(entries, m_largeEntries); } QTEST_MAIN(UDSEntryBenchmark) #include "udsentrybenchmark.moc"