File indexing completed on 2024-04-21 03:54:57

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