File indexing completed on 2025-01-12 12:29:35
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"