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"