File indexing completed on 2024-04-21 14:59:47

0001 /*
0002     This file is part of the KDE project
0003     SPDX-FileCopyrightText: 2004-2014 David Faure <faure@kde.org>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 #include <QTest>
0009 
0010 #include <QHash>
0011 #include <QList>
0012 #include <QMap>
0013 #include <QVector>
0014 
0015 #include <kio/global.h> // filesize_t
0016 #include <kio/udsentry.h>
0017 
0018 /*
0019    This is to compare the old list-of-lists API vs a QMap/QHash-based API
0020    in terms of performance.
0021 
0022    The number of atoms and their type map to what kio_file would put in
0023    for any normal file.
0024 
0025    The lookups are done for two atoms that are present, and for one that is not.
0026 */
0027 
0028 class UdsEntryBenchmark : public QObject
0029 {
0030     Q_OBJECT
0031 public:
0032     UdsEntryBenchmark()
0033         : nameStr(QStringLiteral("name"))
0034         , now(QDateTime::currentDateTime())
0035         , now_time_t(now.toSecsSinceEpoch())
0036     {
0037     }
0038 private Q_SLOTS:
0039     void testKDE3Slave();
0040     void testKDE3App();
0041     void testHashVariantSlave();
0042     void testHashVariantApp();
0043     void testHashStructSlave();
0044     void testHashStructApp();
0045     void testMapStructSlave();
0046     void testMapStructApp();
0047     void testTwoVectorsSlaveFill();
0048     void testTwoVectorsSlaveCompare();
0049     void testTwoVectorsApp();
0050     void testAnotherSlaveFill();
0051     void testAnotherSlaveCompare();
0052     void testAnotherApp();
0053     void testAnotherV2SlaveFill();
0054     void testAnotherV2SlaveCompare();
0055     void testAnotherV2App();
0056 
0057 private:
0058     const QString nameStr;
0059     const QDateTime now;
0060     const time_t now_time_t;
0061 };
0062 
0063 class OldUDSAtom
0064 {
0065 public:
0066     QString m_str;
0067     long long m_long;
0068     unsigned int m_uds;
0069 };
0070 typedef QList<OldUDSAtom> OldUDSEntry; // well it was a QValueList :)
0071 
0072 static void fillOldUDSEntry(OldUDSEntry &entry, time_t now_time_t, const QString &nameStr)
0073 {
0074     OldUDSAtom atom;
0075     atom.m_uds = KIO::UDSEntry::UDS_NAME;
0076     atom.m_str = nameStr;
0077     entry.append(atom);
0078     atom.m_uds = KIO::UDSEntry::UDS_SIZE;
0079     atom.m_long = 123456ULL;
0080     entry.append(atom);
0081     atom.m_uds = KIO::UDSEntry::UDS_MODIFICATION_TIME;
0082     atom.m_long = now_time_t;
0083     entry.append(atom);
0084     atom.m_uds = KIO::UDSEntry::UDS_ACCESS_TIME;
0085     atom.m_long = now_time_t;
0086     entry.append(atom);
0087     atom.m_uds = KIO::UDSEntry::UDS_FILE_TYPE;
0088     atom.m_long = S_IFREG;
0089     entry.append(atom);
0090     atom.m_uds = KIO::UDSEntry::UDS_ACCESS;
0091     atom.m_long = 0644;
0092     entry.append(atom);
0093     atom.m_uds = KIO::UDSEntry::UDS_USER;
0094     atom.m_str = nameStr;
0095     entry.append(atom);
0096     atom.m_uds = KIO::UDSEntry::UDS_GROUP;
0097     atom.m_str = nameStr;
0098     entry.append(atom);
0099 }
0100 
0101 void UdsEntryBenchmark::testKDE3Slave()
0102 {
0103     QBENCHMARK {
0104         OldUDSEntry entry;
0105         fillOldUDSEntry(entry, now_time_t, nameStr);
0106         QCOMPARE(entry.count(), 8);
0107     }
0108 }
0109 
0110 void UdsEntryBenchmark::testKDE3App()
0111 {
0112     OldUDSEntry entry;
0113     fillOldUDSEntry(entry, now_time_t, nameStr);
0114 
0115     QString displayName;
0116     KIO::filesize_t size;
0117     QString url;
0118 
0119     QBENCHMARK {
0120         OldUDSEntry::ConstIterator it2 = entry.constBegin();
0121         for (; it2 != entry.constEnd(); it2++) {
0122             switch ((*it2).m_uds) {
0123             case KIO::UDSEntry::UDS_NAME:
0124                 displayName = (*it2).m_str;
0125                 break;
0126             case KIO::UDSEntry::UDS_URL:
0127                 url = (*it2).m_str;
0128                 break;
0129             case KIO::UDSEntry::UDS_SIZE:
0130                 size = (*it2).m_long;
0131                 break;
0132             }
0133         }
0134         QCOMPARE(size, 123456ULL);
0135         QCOMPARE(displayName, QStringLiteral("name"));
0136         QVERIFY(url.isEmpty());
0137     }
0138 }
0139 
0140 // QHash or QMap? doesn't seem to make much difference.
0141 typedef QHash<uint, QVariant> UDSEntryHV;
0142 
0143 // This uses QDateTime instead of time_t
0144 static void fillUDSEntryHV(UDSEntryHV &entry, const QDateTime &now, const QString &nameStr)
0145 {
0146     entry.reserve(8);
0147     entry.insert(KIO::UDSEntry::UDS_NAME, nameStr);
0148     // we might need a method to make sure people use unsigned long long
0149     entry.insert(KIO::UDSEntry::UDS_SIZE, 123456ULL);
0150     entry.insert(KIO::UDSEntry::UDS_MODIFICATION_TIME, now);
0151     entry.insert(KIO::UDSEntry::UDS_ACCESS_TIME, now);
0152     entry.insert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFREG);
0153     entry.insert(KIO::UDSEntry::UDS_ACCESS, 0644);
0154     entry.insert(KIO::UDSEntry::UDS_USER, nameStr);
0155     entry.insert(KIO::UDSEntry::UDS_GROUP, nameStr);
0156 }
0157 
0158 void UdsEntryBenchmark::testHashVariantSlave()
0159 {
0160     const QDateTime now = QDateTime::currentDateTime();
0161     QBENCHMARK {
0162         UDSEntryHV entry;
0163         fillUDSEntryHV(entry, now, nameStr);
0164         QCOMPARE(entry.count(), 8);
0165     }
0166 }
0167 
0168 void UdsEntryBenchmark::testHashVariantApp()
0169 {
0170     // Normally the code would look like this, but let's change it to time it like the old api
0171     /*
0172        QString displayName = entry.value( KIO::UDSEntry::UDS_NAME ).toString();
0173        QUrl url = entry.value( KIO::UDSEntry::UDS_URL ).toString();
0174        KIO::filesize_t size = entry.value( KIO::UDSEntry::UDS_SIZE ).toULongLong();
0175      */
0176     UDSEntryHV entry;
0177     fillUDSEntryHV(entry, now, nameStr);
0178 
0179     QString displayName;
0180     KIO::filesize_t size;
0181     QString url;
0182 
0183     QBENCHMARK {
0184         // For a field that we assume to always be there
0185         displayName = entry.value(KIO::UDSEntry::UDS_NAME).toString();
0186 
0187         // For a field that might not be there
0188         auto it = entry.constFind(KIO::UDSEntry::UDS_URL);
0189         const auto end = entry.cend();
0190         if (it != end) {
0191             url = it.value().toString();
0192         }
0193 
0194         it = entry.constFind(KIO::UDSEntry::UDS_SIZE);
0195         if (it != end) {
0196             size = it.value().toULongLong();
0197         }
0198 
0199         QCOMPARE(size, 123456ULL);
0200         QCOMPARE(displayName, QStringLiteral("name"));
0201         QVERIFY(url.isEmpty());
0202     }
0203 }
0204 
0205 // The KDE4 solution: QHash+struct
0206 
0207 // Which one is used depends on UDS_STRING vs UDS_LONG
0208 struct UDSAtom4 { // can't be a union due to qstring...
0209     UDSAtom4()
0210     {
0211     } // for QHash or QMap
0212     UDSAtom4(const QString &s)
0213         : m_str(s)
0214     {
0215     }
0216     UDSAtom4(long long l)
0217         : m_long(l)
0218     {
0219     }
0220 
0221     QString m_str;
0222     long long m_long;
0223 };
0224 
0225 // Another possibility, to save on QVariant costs
0226 typedef QHash<uint, UDSAtom4> UDSEntryHS; // hash+struct
0227 
0228 static void fillQHashStructEntry(UDSEntryHS &entry, time_t now_time_t, const QString &nameStr)
0229 {
0230     entry.reserve(8);
0231     entry.insert(KIO::UDSEntry::UDS_NAME, nameStr);
0232     entry.insert(KIO::UDSEntry::UDS_SIZE, 123456ULL);
0233     entry.insert(KIO::UDSEntry::UDS_MODIFICATION_TIME, now_time_t);
0234     entry.insert(KIO::UDSEntry::UDS_ACCESS_TIME, now_time_t);
0235     entry.insert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFREG);
0236     entry.insert(KIO::UDSEntry::UDS_ACCESS, 0644);
0237     entry.insert(KIO::UDSEntry::UDS_USER, nameStr);
0238     entry.insert(KIO::UDSEntry::UDS_GROUP, nameStr);
0239 }
0240 void UdsEntryBenchmark::testHashStructSlave()
0241 {
0242     QBENCHMARK {
0243         UDSEntryHS entry;
0244         fillQHashStructEntry(entry, now_time_t, nameStr);
0245         QCOMPARE(entry.count(), 8);
0246     }
0247 }
0248 
0249 void UdsEntryBenchmark::testHashStructApp()
0250 {
0251     UDSEntryHS entry;
0252     fillQHashStructEntry(entry, now_time_t, nameStr);
0253 
0254     QString displayName;
0255     KIO::filesize_t size;
0256     QString url;
0257 
0258     QBENCHMARK {
0259         // For a field that we assume to always be there
0260         displayName = entry.value(KIO::UDSEntry::UDS_NAME).m_str;
0261 
0262         // For a field that might not be there
0263         auto it = entry.constFind(KIO::UDSEntry::UDS_URL);
0264         const auto end = entry.cend();
0265         if (it != end) {
0266             url = it.value().m_str;
0267         }
0268 
0269         it = entry.constFind(KIO::UDSEntry::UDS_SIZE);
0270         if (it != end) {
0271             size = it.value().m_long;
0272         }
0273         QCOMPARE(size, 123456ULL);
0274         QCOMPARE(displayName, QStringLiteral("name"));
0275         QVERIFY(url.isEmpty());
0276     }
0277 }
0278 
0279 // Let's see if QMap makes any difference
0280 typedef QMap<uint, UDSAtom4> UDSEntryMS; // map+struct
0281 
0282 static void fillQMapStructEntry(UDSEntryMS &entry, time_t now_time_t, const QString &nameStr)
0283 {
0284     entry.insert(KIO::UDSEntry::UDS_NAME, nameStr);
0285     entry.insert(KIO::UDSEntry::UDS_SIZE, 123456ULL);
0286     entry.insert(KIO::UDSEntry::UDS_MODIFICATION_TIME, now_time_t);
0287     entry.insert(KIO::UDSEntry::UDS_ACCESS_TIME, now_time_t);
0288     entry.insert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFREG);
0289     entry.insert(KIO::UDSEntry::UDS_ACCESS, 0644);
0290     entry.insert(KIO::UDSEntry::UDS_USER, nameStr);
0291     entry.insert(KIO::UDSEntry::UDS_GROUP, nameStr);
0292 }
0293 
0294 void UdsEntryBenchmark::testMapStructSlave()
0295 {
0296     QBENCHMARK {
0297         UDSEntryMS entry;
0298         fillQMapStructEntry(entry, now_time_t, nameStr);
0299         QCOMPARE(entry.count(), 8);
0300     }
0301 }
0302 
0303 void UdsEntryBenchmark::testMapStructApp()
0304 {
0305     UDSEntryMS entry;
0306     fillQMapStructEntry(entry, now_time_t, nameStr);
0307 
0308     QString displayName;
0309     KIO::filesize_t size;
0310     QString url;
0311 
0312     QBENCHMARK {
0313         // For a field that we assume to always be there
0314         displayName = entry.value(KIO::UDSEntry::UDS_NAME).m_str;
0315 
0316         // For a field that might not be there
0317         auto it = entry.constFind(KIO::UDSEntry::UDS_URL);
0318         const auto end = entry.cend();
0319         if (it != end) {
0320             url = it.value().m_str;
0321         }
0322 
0323         it = entry.constFind(KIO::UDSEntry::UDS_SIZE);
0324         if (it != end) {
0325             size = it.value().m_long;
0326         }
0327 
0328         QCOMPARE(size, 123456ULL);
0329         QCOMPARE(displayName, QStringLiteral("name"));
0330         QVERIFY(url.isEmpty());
0331     }
0332 }
0333 
0334 // Frank's suggestion in https://git.reviewboard.kde.org/r/118452/
0335 class FrankUDSEntry
0336 {
0337 public:
0338     class Field
0339     {
0340     public:
0341         inline Field(const QString &value)
0342             : m_str(value)
0343             , m_long(0)
0344         {
0345         }
0346         inline Field(long long value = 0)
0347             : m_long(value)
0348         {
0349         }
0350         QString m_str;
0351         long long m_long;
0352     };
0353     QVector<Field> fields;
0354     // If udsIndexes[i] == uds, then fields[i] contains the value for 'uds'.
0355     QVector<uint> udsIndexes;
0356 
0357     void reserve(int size)
0358     {
0359         fields.reserve(size);
0360         udsIndexes.reserve(size);
0361     }
0362     void insert(uint udsField, const QString &value)
0363     {
0364         const int index = udsIndexes.indexOf(udsField);
0365         if (index >= 0) {
0366             fields[index] = Field(value);
0367         } else {
0368             udsIndexes.append(udsField);
0369             fields.append(Field(value));
0370         }
0371     }
0372     void replaceOrInsert(uint udsField, const QString &value)
0373     {
0374         insert(udsField, value);
0375     }
0376     void insert(uint udsField, long long value)
0377     {
0378         const int index = udsIndexes.indexOf(udsField);
0379         if (index >= 0) {
0380             fields[index] = Field(value);
0381         } else {
0382             udsIndexes.append(udsField);
0383             fields.append(Field(value));
0384         }
0385     }
0386     void replaceOrInsert(uint udsField, long long value)
0387     {
0388         insert(udsField, value);
0389     }
0390     int count() const
0391     {
0392         return udsIndexes.count();
0393     }
0394     QString stringValue(uint udsField) const
0395     {
0396         const int index = udsIndexes.indexOf(udsField);
0397         if (index >= 0) {
0398             return fields.at(index).m_str;
0399         } else {
0400             return QString();
0401         }
0402     }
0403     long long numberValue(uint udsField, long long defaultValue = -1) const
0404     {
0405         const int index = udsIndexes.indexOf(udsField);
0406         if (index >= 0) {
0407             return fields.at(index).m_long;
0408         } else {
0409             return defaultValue;
0410         }
0411     }
0412 };
0413 
0414 template<class T>
0415 static void fillUDSEntries(T &entry, time_t now_time_t, const QString &nameStr)
0416 {
0417     entry.reserve(8);
0418     // In random order of index
0419     entry.insert(KIO::UDSEntry::UDS_ACCESS_TIME, now_time_t);
0420     entry.insert(KIO::UDSEntry::UDS_MODIFICATION_TIME, now_time_t);
0421     entry.insert(KIO::UDSEntry::UDS_SIZE, 123456ULL);
0422     entry.insert(KIO::UDSEntry::UDS_NAME, nameStr);
0423     entry.insert(KIO::UDSEntry::UDS_GROUP, nameStr);
0424     entry.insert(KIO::UDSEntry::UDS_USER, nameStr);
0425     entry.insert(KIO::UDSEntry::UDS_ACCESS, 0644);
0426     entry.insert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFREG);
0427 }
0428 
0429 template<class T>
0430 void testFill(time_t now_time_t, const QString &nameStr)
0431 {
0432     QBENCHMARK {
0433         T entry;
0434         fillUDSEntries<T>(entry, now_time_t, nameStr);
0435         QCOMPARE(entry.count(), 8);
0436     }
0437 }
0438 
0439 template<class T>
0440 void testCompare(time_t now_time_t, const QString &nameStr)
0441 {
0442     T entry;
0443     T entry2;
0444     fillUDSEntries<T>(entry, now_time_t, nameStr);
0445     fillUDSEntries<T>(entry2, now_time_t, nameStr);
0446     QCOMPARE(entry.count(), 8);
0447     QCOMPARE(entry2.count(), 8);
0448     QBENCHMARK {
0449         bool equal = entry.stringValue(KIO::UDSEntry::UDS_NAME) == entry2.stringValue(KIO::UDSEntry::UDS_NAME)
0450             && entry.numberValue(KIO::UDSEntry::UDS_SIZE) == entry2.numberValue(KIO::UDSEntry::UDS_SIZE)
0451             && entry.numberValue(KIO::UDSEntry::UDS_MODIFICATION_TIME) == entry2.numberValue(KIO::UDSEntry::UDS_MODIFICATION_TIME)
0452             && entry.numberValue(KIO::UDSEntry::UDS_ACCESS_TIME) == entry2.numberValue(KIO::UDSEntry::UDS_ACCESS_TIME)
0453             && entry.numberValue(KIO::UDSEntry::UDS_FILE_TYPE) == entry2.numberValue(KIO::UDSEntry::UDS_FILE_TYPE)
0454             && entry.numberValue(KIO::UDSEntry::UDS_ACCESS) == entry2.numberValue(KIO::UDSEntry::UDS_ACCESS)
0455             && entry.stringValue(KIO::UDSEntry::UDS_USER) == entry2.stringValue(KIO::UDSEntry::UDS_USER)
0456             && entry.stringValue(KIO::UDSEntry::UDS_GROUP) == entry2.stringValue(KIO::UDSEntry::UDS_GROUP);
0457         QVERIFY(equal);
0458     }
0459 }
0460 
0461 template<class T>
0462 void testApp(time_t now_time_t, const QString &nameStr)
0463 {
0464     T entry;
0465     fillUDSEntries<T>(entry, now_time_t, nameStr);
0466 
0467     QString displayName;
0468     KIO::filesize_t size;
0469     QString url;
0470 
0471     QBENCHMARK {
0472         displayName = entry.stringValue(KIO::UDSEntry::UDS_NAME);
0473         url = entry.stringValue(KIO::UDSEntry::UDS_URL);
0474         size = entry.numberValue(KIO::UDSEntry::UDS_SIZE);
0475         QCOMPARE(size, 123456ULL);
0476         QCOMPARE(displayName, QStringLiteral("name"));
0477         QVERIFY(url.isEmpty());
0478     }
0479 }
0480 
0481 void UdsEntryBenchmark::testTwoVectorsSlaveFill()
0482 {
0483     testFill<FrankUDSEntry>(now_time_t, nameStr);
0484 }
0485 void UdsEntryBenchmark::testTwoVectorsSlaveCompare()
0486 {
0487     testCompare<FrankUDSEntry>(now_time_t, nameStr);
0488 }
0489 void UdsEntryBenchmark::testTwoVectorsApp()
0490 {
0491     testApp<FrankUDSEntry>(now_time_t, nameStr);
0492 }
0493 
0494 // Instead of two vectors, use only one
0495 class AnotherUDSEntry
0496 {
0497 private:
0498     struct Field {
0499         inline Field()
0500         {
0501         }
0502         inline Field(const uint index, const QString &value)
0503             : m_str(value)
0504             , m_index(index)
0505         {
0506         }
0507         inline Field(const uint index, long long value = 0)
0508             : m_long(value)
0509             , m_index(index)
0510         {
0511         }
0512         // This operator helps to gain 1ms just comparing the key
0513         inline bool operator==(const Field &other) const
0514         {
0515             return m_index == other.m_index;
0516         }
0517 
0518         QString m_str;
0519         long long m_long = LLONG_MIN;
0520         uint m_index = 0;
0521     };
0522     std::vector<Field> storage;
0523 
0524 public:
0525     void reserve(int size)
0526     {
0527         storage.reserve(size);
0528     }
0529     void insert(uint udsField, const QString &value)
0530     {
0531         Q_ASSERT(udsField & KIO::UDSEntry::UDS_STRING);
0532         Q_ASSERT(std::find_if(storage.cbegin(),
0533                               storage.cend(),
0534                               [udsField](const Field &entry) {
0535                                   return entry.m_index == udsField;
0536                               })
0537                  == storage.cend());
0538         storage.emplace_back(udsField, value);
0539     }
0540     void replaceOrInsert(uint udsField, const QString &value)
0541     {
0542         Q_ASSERT(udsField & KIO::UDSEntry::UDS_STRING);
0543         auto it = std::find_if(storage.begin(), storage.end(), [udsField](const Field &entry) {
0544             return entry.m_index == udsField;
0545         });
0546         if (it != storage.end()) {
0547             it->m_str = value;
0548             return;
0549         }
0550         storage.emplace_back(udsField, value);
0551     }
0552     void insert(uint udsField, long long value)
0553     {
0554         Q_ASSERT(udsField & KIO::UDSEntry::UDS_NUMBER);
0555         Q_ASSERT(std::find_if(storage.cbegin(),
0556                               storage.cend(),
0557                               [udsField](const Field &entry) {
0558                                   return entry.m_index == udsField;
0559                               })
0560                  == storage.cend());
0561         storage.emplace_back(udsField, value);
0562     }
0563     void replaceOrInsert(uint udsField, long long value)
0564     {
0565         Q_ASSERT(udsField & KIO::UDSEntry::UDS_NUMBER);
0566         auto it = std::find_if(storage.begin(), storage.end(), [udsField](const Field &entry) {
0567             return entry.m_index == udsField;
0568         });
0569         if (it != storage.end()) {
0570             it->m_long = value;
0571             return;
0572         }
0573         storage.emplace_back(udsField, value);
0574     }
0575     int count() const
0576     {
0577         return storage.size();
0578     }
0579     QString stringValue(uint udsField) const
0580     {
0581         auto it = std::find_if(storage.cbegin(), storage.cend(), [udsField](const Field &entry) {
0582             return entry.m_index == udsField;
0583         });
0584         if (it != storage.cend()) {
0585             return it->m_str;
0586         }
0587         return QString();
0588     }
0589     long long numberValue(uint udsField, long long defaultValue = -1) const
0590     {
0591         auto it = std::find_if(storage.cbegin(), storage.cend(), [udsField](const Field &entry) {
0592             return entry.m_index == udsField;
0593         });
0594         if (it != storage.cend()) {
0595             return it->m_long;
0596         }
0597         return defaultValue;
0598     }
0599 };
0600 Q_DECLARE_TYPEINFO(AnotherUDSEntry, Q_MOVABLE_TYPE);
0601 
0602 void UdsEntryBenchmark::testAnotherSlaveFill()
0603 {
0604     testFill<AnotherUDSEntry>(now_time_t, nameStr);
0605 }
0606 void UdsEntryBenchmark::testAnotherSlaveCompare()
0607 {
0608     testCompare<AnotherUDSEntry>(now_time_t, nameStr);
0609 }
0610 void UdsEntryBenchmark::testAnotherApp()
0611 {
0612     testApp<AnotherUDSEntry>(now_time_t, nameStr);
0613 }
0614 
0615 // Instead of two vectors, use only one sorted by index and accessed using a binary search.
0616 class AnotherV2UDSEntry
0617 {
0618 private:
0619     struct Field {
0620         inline Field()
0621         {
0622         }
0623         inline Field(const uint index, const QString &value)
0624             : m_str(value)
0625             , m_index(index)
0626         {
0627         }
0628         inline Field(const uint index, long long value = 0)
0629             : m_long(value)
0630             , m_index(index)
0631         {
0632         }
0633         // This operator helps to gain 1ms just comparing the key
0634         inline bool operator==(const Field &other) const
0635         {
0636             return m_index == other.m_index;
0637         }
0638 
0639         QString m_str;
0640         long long m_long = LLONG_MIN;
0641         uint m_index = 0;
0642     };
0643     std::vector<Field> storage;
0644 
0645 private:
0646     static inline bool less(const Field &other, const uint index)
0647     {
0648         return other.m_index < index;
0649     }
0650 
0651 public:
0652     void reserve(int size)
0653     {
0654         storage.reserve(size);
0655     }
0656     void insert(uint udsField, const QString &value)
0657     {
0658         Q_ASSERT(udsField & KIO::UDSEntry::UDS_STRING);
0659         auto it = std::lower_bound(storage.cbegin(), storage.cend(), udsField, less);
0660         Q_ASSERT(it == storage.cend() || it->m_index != udsField);
0661         storage.insert(it, Field(udsField, value));
0662     }
0663     void replaceOrInsert(uint udsField, const QString &value)
0664     {
0665         Q_ASSERT(udsField & KIO::UDSEntry::UDS_STRING);
0666         auto it = std::lower_bound(storage.begin(), storage.end(), udsField, less);
0667         if (it != storage.end() && it->m_index == udsField) {
0668             it->m_str = value;
0669             return;
0670         }
0671         storage.insert(it, Field(udsField, value));
0672     }
0673     void insert(uint udsField, long long value)
0674     {
0675         Q_ASSERT(udsField & KIO::UDSEntry::UDS_NUMBER);
0676         auto it = std::lower_bound(storage.cbegin(), storage.cend(), udsField, less);
0677         Q_ASSERT(it == storage.end() || it->m_index != udsField);
0678         storage.insert(it, Field(udsField, value));
0679     }
0680     void replaceOrInsert(uint udsField, long long value)
0681     {
0682         Q_ASSERT(udsField & KIO::UDSEntry::UDS_NUMBER);
0683         auto it = std::lower_bound(storage.begin(), storage.end(), udsField, less);
0684         if (it != storage.end() && it->m_index == udsField) {
0685             it->m_long = value;
0686             return;
0687         }
0688         storage.insert(it, Field(udsField, value));
0689     }
0690     int count() const
0691     {
0692         return storage.size();
0693     }
0694     QString stringValue(uint udsField) const
0695     {
0696         auto it = std::lower_bound(storage.cbegin(), storage.cend(), udsField, less);
0697         if (it != storage.end() && it->m_index == udsField) {
0698             return it->m_str;
0699         }
0700         return QString();
0701     }
0702     long long numberValue(uint udsField, long long defaultValue = -1) const
0703     {
0704         auto it = std::lower_bound(storage.cbegin(), storage.cend(), udsField, less);
0705         if (it != storage.end() && it->m_index == udsField) {
0706             return it->m_long;
0707         }
0708         return defaultValue;
0709     }
0710 };
0711 Q_DECLARE_TYPEINFO(AnotherV2UDSEntry, Q_MOVABLE_TYPE);
0712 
0713 void UdsEntryBenchmark::testAnotherV2SlaveFill()
0714 {
0715     testFill<AnotherV2UDSEntry>(now_time_t, nameStr);
0716 }
0717 void UdsEntryBenchmark::testAnotherV2SlaveCompare()
0718 {
0719     testCompare<AnotherV2UDSEntry>(now_time_t, nameStr);
0720 }
0721 void UdsEntryBenchmark::testAnotherV2App()
0722 {
0723     testApp<AnotherV2UDSEntry>(now_time_t, nameStr);
0724 }
0725 
0726 QTEST_MAIN(UdsEntryBenchmark)
0727 
0728 #include "udsentry_api_comparison_benchmark.moc"