diff --git a/src/core/kfileitem.cpp b/src/core/kfileitem.cpp --- a/src/core/kfileitem.cpp +++ b/src/core/kfileitem.cpp @@ -562,7 +562,7 @@ d->m_strText = KIO::decodeFileName(d->m_strName); } if (d->m_entry.contains(KIO::UDSEntry::UDS_NAME)) { - d->m_entry.insert(KIO::UDSEntry::UDS_NAME, d->m_strName); // #195385 + d->m_entry.replaceOrInsert(KIO::UDSEntry::UDS_NAME, d->m_strName); // #195385 } } diff --git a/src/core/listjob.cpp b/src/core/listjob.cpp --- a/src/core/listjob.cpp +++ b/src/core/listjob.cpp @@ -172,8 +172,8 @@ if ((m_prefix.isNull() || (filename != QLatin1String("..") && filename != QLatin1String("."))) && (includeHidden || (filename[0] != '.'))) { // ## Didn't find a way to use the iterator instead of re-doing a key lookup - newone.insert(KIO::UDSEntry::UDS_NAME, m_prefix + filename); - newone.insert(KIO::UDSEntry::UDS_DISPLAY_NAME, m_displayPrefix + displayName); + newone.replaceOrInsert(KIO::UDSEntry::UDS_NAME, m_prefix + filename); + newone.replaceOrInsert(KIO::UDSEntry::UDS_DISPLAY_NAME, m_displayPrefix + displayName); newlist.append(newone); } } diff --git a/src/core/udsentry.h b/src/core/udsentry.h --- a/src/core/udsentry.h +++ b/src/core/udsentry.h @@ -311,6 +311,26 @@ friend class UDSEntryPrivate; friend void ::debugUDSEntry(QDebug stream, const KIO::UDSEntry &entry); QSharedDataPointer d; +public: + /** + * insert field with string value + * @param field numeric field id + * @param value to set + */ + void replaceOrInsert(uint field, const QString &value); + + /** + * insert field with numeric value + * @param field numeric field id + * @param l value to set + */ + void replaceOrInsert(uint field, long long l); + + /** + * @param field numeric field id + * @return the name of the field + */ + static QString nameOfUdsField(uint field); }; } diff --git a/src/core/udsentry.cpp b/src/core/udsentry.cpp --- a/src/core/udsentry.cpp +++ b/src/core/udsentry.cpp @@ -37,29 +37,109 @@ class KIO::UDSEntryPrivate : public QSharedData { public: - struct Field { - inline Field(const QString &value) : m_str(value), m_long(0) {} - inline Field(long long value = 0) : m_long(value) { } + struct Field + { + inline Field() {} + inline Field(const uint index, const QString &value) : m_str(value), m_index(index) {} + inline Field(const uint index, long long value = 0) : m_long(value), m_index(index) {} + // This operator helps to gain 1ms just comparing the key + inline bool operator == (const Field &other) const { + return m_index == other.m_index; + } + QString m_str; - long long m_long; + long long m_long = LLONG_MIN; + uint m_index = 0; }; - - QVector fields; - - // If udsIndexes[i] == uds, then fields[i] contains the value for 'uds'. Example: - // udsIndexes = {UDS_NAME, UDS_FILE_SIZE, ...} - // fields = {Field("filename"), Field(1234), ...} - QVector udsIndexes; - - void insert(uint uds, const Field& field) + std::vector storage; +public: + void reserve(int size) { - const int index = udsIndexes.indexOf(uds); - if (index >= 0) { - fields[index] = field; - } else { - udsIndexes.append(uds); - fields.append(field); + storage.reserve(size); + } + void insert(uint udsField, const QString &value) + { + Q_ASSERT(udsField & KIO::UDSEntry::UDS_STRING); + Q_ASSERT(std::find_if(storage.cbegin(), storage.cend(), + [udsField](const Field &entry) {return entry.m_index == udsField;}) == storage.cend()); + storage.emplace_back(udsField, value); + } + void replaceOrInsert(uint udsField, const QString &value) + { + Q_ASSERT(udsField & KIO::UDSEntry::UDS_STRING); + auto it = std::find_if(storage.begin(), storage.end(), + [udsField](const Field &entry) {return entry.m_index == udsField;}); + if (it != storage.end()) { + it->m_str = value; + return; + } + storage.emplace_back(udsField, value); + } + void insert(uint udsField, long long value) + { + Q_ASSERT(udsField & KIO::UDSEntry::UDS_NUMBER); + Q_ASSERT(std::find_if(storage.cbegin(), storage.cend(), + [udsField](const Field &entry) {return entry.m_index == udsField;}) == storage.cend()); + storage.emplace_back(udsField, value); + } + void replaceOrInsert(uint udsField, long long value) + { + Q_ASSERT(udsField & KIO::UDSEntry::UDS_NUMBER); + auto it = std::find_if(storage.begin(), storage.end(), + [udsField](const Field &entry) {return entry.m_index == udsField;}); + if (it != storage.end()) { + it->m_long = value; + return; + } + storage.emplace_back(udsField, value); + } + int count() const + { + return storage.size(); + } + QString stringValue(uint udsField) const + { + auto it = std::find_if(storage.cbegin(), storage.cend(), + [udsField](const Field &entry) {return entry.m_index == udsField;}); + if (it != storage.cend()) { + return it->m_str; } + return QString(); + } + long long numberValue(uint udsField, long long defaultValue = -1) const + { + auto it = std::find_if(storage.cbegin(), storage.cend(), + [udsField](const Field &entry) {return entry.m_index == udsField;}); + if (it != storage.cend()) { + return it->m_long; + } + return defaultValue; + } + QList listFields() const + { + QList res; + for (auto it = storage.cbegin(), end = storage.cend(); it != end; ++it) { + res.append(it->m_index); + } + return res; + } + QVector fields() const + { + QVector res; + for (auto it = storage.cbegin(), end = storage.cend(); it != end; ++it) { + res.append(it->m_index); + } + return res; + } + bool contains(uint udsField) const + { + auto it = std::find_if(storage.cbegin(), storage.cend(), + [udsField](const Field &entry) {return entry.m_index == udsField;}); + return (it != storage.cend()); + } + void clear() + { + storage.clear(); } static void save(QDataStream &, const UDSEntry &); @@ -99,22 +179,12 @@ QString UDSEntry::stringValue(uint field) const { - const int index = d->udsIndexes.indexOf(field); - if (index >= 0) { - return d->fields.at(index).m_str; - } else { - return QString(); - } + return d->stringValue(field); } long long UDSEntry::numberValue(uint field, long long defaultValue) const { - const int index = d->udsIndexes.indexOf(field); - if (index >= 0) { - return d->fields.at(index).m_long; - } else { - return defaultValue; - } + return d->numberValue(field, defaultValue); } bool UDSEntry::isDir() const @@ -129,46 +199,44 @@ void UDSEntry::reserve(int size) { - d->fields.reserve(size); - d->udsIndexes.reserve(size); + d->reserve(size); } void UDSEntry::insert(uint field, const QString &value) { - d->insert(field, UDSEntryPrivate::Field(value)); + d->insert(field, value); } void UDSEntry::insert(uint field, long long value) { - d->insert(field, UDSEntryPrivate::Field(value)); + d->insert(field, value); } #ifndef KIOCORE_NO_DEPRECATED QList UDSEntry::listFields() const { - return d->udsIndexes.toList(); + return d->listFields(); } #endif QVector UDSEntry::fields() const { - return d->udsIndexes; + return d->fields(); } int UDSEntry::count() const { - return d->udsIndexes.count(); + return d->count(); } bool UDSEntry::contains(uint field) const { - return d->udsIndexes.contains(field); + return d->contains(field); } void UDSEntry::clear() { - d->fields.clear(); - d->udsIndexes.clear(); + d->clear(); } QDataStream &operator<<(QDataStream &s, const UDSEntry &a) @@ -185,20 +253,19 @@ void UDSEntryPrivate::save(QDataStream &s, const UDSEntry &a) { - const QVector &udsIndexes = a.d->udsIndexes; - const QVector &fields = a.d->fields; - const int size = udsIndexes.size(); + const int size = a.d->count(); s << size; - for (int index = 0; index < size; ++index) { - uint uds = udsIndexes.at(index); + for (auto it = a.d->storage.cbegin(), end = a.d->storage.cend(); it != end; ++it) + { + uint uds = it->m_index; s << uds; if (uds & KIO::UDSEntry::UDS_STRING) { - s << fields.at(index).m_str; + s << it->m_str; } else if (uds & KIO::UDSEntry::UDS_NUMBER) { - s << fields.at(index).m_long; + s << it->m_long; } else { Q_ASSERT_X(false, "KIO::UDSEntry", "Found a field with an invalid type"); } @@ -215,13 +282,9 @@ { a.clear(); - QVector &fields = a.d->fields; - QVector &udsIndexes = a.d->udsIndexes; - quint32 size; s >> size; - fields.reserve(size); - udsIndexes.reserve(size); + a.d->reserve(size); // We cache the loaded strings. Some of them, like, e.g., the user, // will often be the same for many entries in a row. Caching them @@ -234,7 +297,6 @@ for (quint32 i = 0; i < size; ++i) { quint32 uds; s >> uds; - udsIndexes.append(uds); if (uds & KIO::UDSEntry::UDS_STRING) { // If the QString is the same like the one we read for the @@ -247,34 +309,108 @@ cachedStrings[i] = buffer; } - fields.append(Field(cachedStrings.at(i))); + a.d->insert(uds, cachedStrings.at(i)); } else if (uds & KIO::UDSEntry::UDS_NUMBER) { long long value; s >> value; - fields.append(Field(value)); + a.d->insert(uds, value); } else { Q_ASSERT_X(false, "KIO::UDSEntry", "Found a field with an invalid type"); } } } void debugUDSEntry(QDebug stream, const KIO::UDSEntry &entry) { - const QVector &udsIndexes = entry.d->udsIndexes; - const QVector &fields = entry.d->fields; - const int size = udsIndexes.size(); QDebugStateSaver saver(stream); stream.nospace() << "["; - for (int index = 0; index < size; ++index) { - const uint uds = udsIndexes.at(index); - stream << " " << (uds & 0xffff) << "="; // we could use a switch statement for readability :-) - if (uds & KIO::UDSEntry::UDS_STRING) { - stream << fields.at(index).m_str; - } else if (uds & KIO::UDSEntry::UDS_NUMBER) { - stream << fields.at(index).m_long; + for (auto it = entry.d->storage.cbegin(), end = entry.d->storage.cend(); it != end; ++it) { + stream << " " << UDSEntry::nameOfUdsField(it->m_index) << "="; + if (it->m_index & KIO::UDSEntry::UDS_STRING) { + stream << it->m_str; + } else if (it->m_index & KIO::UDSEntry::UDS_NUMBER) { + stream << it->m_long; } else { Q_ASSERT_X(false, "KIO::UDSEntry", "Found a field with an invalid type"); } } stream << " ]"; } + +void UDSEntry::replaceOrInsert(uint field, const QString &value) +{ + d->replaceOrInsert(field, value); +} + +void UDSEntry::replaceOrInsert(uint field, long long value) +{ + d->replaceOrInsert(field, value); +} + +QString UDSEntry::nameOfUdsField(uint field) +{ + switch (field) { + case UDS_SIZE: + return QStringLiteral("UDS_SIZE"); + case UDS_SIZE_LARGE: + return QStringLiteral("UDS_SIZE_LARGE"); + case UDS_USER: + return QStringLiteral("UDS_USER"); + case UDS_ICON_NAME: + return QStringLiteral("UDS_ICON_NAME"); + case UDS_GROUP: + return QStringLiteral("UDS_GROUP"); + case UDS_NAME: + return QStringLiteral("UDS_NAME"); + case UDS_LOCAL_PATH: + return QStringLiteral("UDS_LOCAL_PATH"); + case UDS_HIDDEN: + return QStringLiteral("UDS_HIDDEN"); + case UDS_ACCESS: + return QStringLiteral("UDS_ACCESS"); + case UDS_MODIFICATION_TIME: + return QStringLiteral("UDS_MODIFICATION_TIME"); + case UDS_ACCESS_TIME: + return QStringLiteral("UDS_ACCESS_TIME"); + case UDS_CREATION_TIME: + return QStringLiteral("UDS_CREATION_TIME"); + case UDS_FILE_TYPE: + return QStringLiteral("UDS_FILE_TYPE"); + case UDS_LINK_DEST: + return QStringLiteral("UDS_LINK_DEST"); + case UDS_URL: + return QStringLiteral("UDS_URL"); + case UDS_MIME_TYPE: + return QStringLiteral("UDS_MIME_TYPE"); + case UDS_GUESSED_MIME_TYPE: + return QStringLiteral("UDS_GUESSED_MIME_TYPE"); + case UDS_XML_PROPERTIES: + return QStringLiteral("UDS_XML_PROPERTIES"); + case UDS_EXTENDED_ACL: + return QStringLiteral("UDS_EXTENDED_ACL"); + case UDS_ACL_STRING: + return QStringLiteral("UDS_ACL_STRING"); + case UDS_DEFAULT_ACL_STRING: + return QStringLiteral("UDS_DEFAULT_ACL_STRING"); + case UDS_DISPLAY_NAME: + return QStringLiteral("UDS_DISPLAY_NAME"); + case UDS_TARGET_URL: + return QStringLiteral("UDS_TARGET_URL"); + case UDS_DISPLAY_TYPE: + return QStringLiteral("UDS_DISPLAY_TYPE"); + case UDS_ICON_OVERLAY_NAMES: + return QStringLiteral("UDS_ICON_OVERLAY_NAMES"); + case UDS_COMMENT: + return QStringLiteral("UDS_COMMENT"); + case UDS_DEVICE_ID: + return QStringLiteral("UDS_DEVICE_ID"); + case UDS_INODE: + return QStringLiteral("UDS_INODE"); + case UDS_EXTRA: + return QStringLiteral("UDS_EXTRA"); + case UDS_EXTRA_END: + return QStringLiteral("UDS_EXTRA_END"); + default: + return QString("Unknow uds field %1").arg(field); + } +}