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.replace(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.replace(KIO::UDSEntry::UDS_NAME, m_prefix + filename); + newone.replace(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,22 @@ friend class UDSEntryPrivate; friend void ::debugUDSEntry(QDebug stream, const KIO::UDSEntry &entry); QSharedDataPointer d; +public: + /** + * replace or insert field with string value + * @param field numeric field id + * @param value to set + * @since 5.47 + */ + void replace(uint field, const QString &value); + + /** + * replace or insert field with numeric value + * @param field numeric field id + * @param l value to set + * @since 5.47 + */ + void replace(uint field, long long l); }; } diff --git a/src/core/udsentry.cpp b/src/core/udsentry.cpp --- a/src/core/udsentry.cpp +++ b/src/core/udsentry.cpp @@ -32,40 +32,269 @@ using namespace KIO; -/* ---------- UDSEntry ------------ */ +/* ---------- UDSEntryPrivate ------------ */ 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) { } - QString m_str; - long long m_long; - }; + void reserve(int size) + { + 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 replace(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 replace(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; + } +#ifndef KIOCORE_NO_DEPRECATED + QList listFields() const + { + QList res; + res.reserve(storage.size()); + for (auto it = storage.cbegin(), end = storage.cend(); it != end; ++it) { + res.append(it->m_index); + } + return res; + } +#endif + QVector fields() const + { + QVector res; + res.reserve(storage.size()); + 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 &s, const UDSEntry &a) + { + const int size = a.d->count(); + s << size; + + 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 << it->m_str; + } else if (uds & KIO::UDSEntry::UDS_NUMBER) { + s << it->m_long; + } else { + Q_ASSERT_X(false, "KIO::UDSEntry", "Found a field with an invalid type"); + } + } + } + static void load(QDataStream &s, UDSEntry &a) + { + a.clear(); + + quint32 size; + s >> 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 + // permits to use implicit sharing to save memory. + static QVector cachedStrings; + if (quint32(cachedStrings.size()) < size) { + cachedStrings.resize(size); + } - QVector fields; + for (quint32 i = 0; i < size; ++i) { + quint32 uds; + s >> uds; + + if (uds & KIO::UDSEntry::UDS_STRING) { + // If the QString is the same like the one we read for the + // previous UDSEntry at the i-th position, use an implicitly + // shared copy of the same QString to save memory. + QString buffer; + s >> buffer; + + if (buffer != cachedStrings.at(i)) { + cachedStrings[i] = buffer; + } + + a.d->insert(uds, cachedStrings.at(i)); + } else if (uds & KIO::UDSEntry::UDS_NUMBER) { + long long value; + s >> value; + a.d->insert(uds, value); + } else { + Q_ASSERT_X(false, "KIO::UDSEntry", "Found a field with an invalid type"); + } + } + } - // 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; + /** + * @param field numeric UDS field id + * @return the name of the field + */ + static QString nameOfUdsField(uint field) + { + switch (field) { + case UDSEntry::UDS_SIZE: + return QStringLiteral("UDS_SIZE"); + case UDSEntry::UDS_SIZE_LARGE: + return QStringLiteral("UDS_SIZE_LARGE"); + case UDSEntry::UDS_USER: + return QStringLiteral("UDS_USER"); + case UDSEntry::UDS_ICON_NAME: + return QStringLiteral("UDS_ICON_NAME"); + case UDSEntry::UDS_GROUP: + return QStringLiteral("UDS_GROUP"); + case UDSEntry::UDS_NAME: + return QStringLiteral("UDS_NAME"); + case UDSEntry::UDS_LOCAL_PATH: + return QStringLiteral("UDS_LOCAL_PATH"); + case UDSEntry::UDS_HIDDEN: + return QStringLiteral("UDS_HIDDEN"); + case UDSEntry::UDS_ACCESS: + return QStringLiteral("UDS_ACCESS"); + case UDSEntry::UDS_MODIFICATION_TIME: + return QStringLiteral("UDS_MODIFICATION_TIME"); + case UDSEntry::UDS_ACCESS_TIME: + return QStringLiteral("UDS_ACCESS_TIME"); + case UDSEntry::UDS_CREATION_TIME: + return QStringLiteral("UDS_CREATION_TIME"); + case UDSEntry::UDS_FILE_TYPE: + return QStringLiteral("UDS_FILE_TYPE"); + case UDSEntry::UDS_LINK_DEST: + return QStringLiteral("UDS_LINK_DEST"); + case UDSEntry::UDS_URL: + return QStringLiteral("UDS_URL"); + case UDSEntry::UDS_MIME_TYPE: + return QStringLiteral("UDS_MIME_TYPE"); + case UDSEntry::UDS_GUESSED_MIME_TYPE: + return QStringLiteral("UDS_GUESSED_MIME_TYPE"); + case UDSEntry::UDS_XML_PROPERTIES: + return QStringLiteral("UDS_XML_PROPERTIES"); + case UDSEntry::UDS_EXTENDED_ACL: + return QStringLiteral("UDS_EXTENDED_ACL"); + case UDSEntry::UDS_ACL_STRING: + return QStringLiteral("UDS_ACL_STRING"); + case UDSEntry::UDS_DEFAULT_ACL_STRING: + return QStringLiteral("UDS_DEFAULT_ACL_STRING"); + case UDSEntry::UDS_DISPLAY_NAME: + return QStringLiteral("UDS_DISPLAY_NAME"); + case UDSEntry::UDS_TARGET_URL: + return QStringLiteral("UDS_TARGET_URL"); + case UDSEntry::UDS_DISPLAY_TYPE: + return QStringLiteral("UDS_DISPLAY_TYPE"); + case UDSEntry::UDS_ICON_OVERLAY_NAMES: + return QStringLiteral("UDS_ICON_OVERLAY_NAMES"); + case UDSEntry::UDS_COMMENT: + return QStringLiteral("UDS_COMMENT"); + case UDSEntry::UDS_DEVICE_ID: + return QStringLiteral("UDS_DEVICE_ID"); + case UDSEntry::UDS_INODE: + return QStringLiteral("UDS_INODE"); + case UDSEntry::UDS_EXTRA: + return QStringLiteral("UDS_EXTRA"); + case UDSEntry::UDS_EXTRA_END: + return QStringLiteral("UDS_EXTRA_END"); + default: + return QString("Unknown uds field %1").arg(field); + } + } - void insert(uint uds, const Field& field) + static void debugUDSEntry(QDebug stream, const KIO::UDSEntry &entry) { - const int index = udsIndexes.indexOf(uds); - if (index >= 0) { - fields[index] = field; - } else { - udsIndexes.append(uds); - fields.append(field); + QDebugStateSaver saver(stream); + stream.nospace() << "["; + for (auto it = entry.d->storage.cbegin(), end = entry.d->storage.cend(); it != end; ++it) { + stream << " " << 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 << " ]"; } - static void save(QDataStream &, const UDSEntry &); - static void load(QDataStream &, UDSEntry &); +private: + 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) {} + + QString m_str; + long long m_long = LLONG_MIN; + uint m_index = 0; + }; + std::vector storage; + }; -Q_DECLARE_TYPEINFO(KIO::UDSEntryPrivate::Field, Q_MOVABLE_TYPE); + +/* ---------- UDSEntry ------------ */ UDSEntry::UDSEntry() : d(new UDSEntryPrivate()) @@ -99,22 +328,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 +348,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) @@ -183,98 +400,18 @@ return s; } -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(); - - s << size; - - for (int index = 0; index < size; ++index) { - uint uds = udsIndexes.at(index); - s << uds; - - if (uds & KIO::UDSEntry::UDS_STRING) { - s << fields.at(index).m_str; - } else if (uds & KIO::UDSEntry::UDS_NUMBER) { - s << fields.at(index).m_long; - } else { - Q_ASSERT_X(false, "KIO::UDSEntry", "Found a field with an invalid type"); - } - } -} - KIOCORE_EXPORT QDebug operator<<(QDebug stream, const KIO::UDSEntry &entry) { - debugUDSEntry(stream, entry); + UDSEntryPrivate::debugUDSEntry(stream, entry); return stream; } -void UDSEntryPrivate::load(QDataStream &s, UDSEntry &a) +void UDSEntry::replace(uint field, const QString &value) { - a.clear(); - - QVector &fields = a.d->fields; - QVector &udsIndexes = a.d->udsIndexes; - - quint32 size; - s >> size; - fields.reserve(size); - udsIndexes.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 - // permits to use implicit sharing to save memory. - static QVector cachedStrings; - if (quint32(cachedStrings.size()) < size) { - cachedStrings.resize(size); - } - - 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 - // previous UDSEntry at the i-th position, use an implicitly - // shared copy of the same QString to save memory. - QString buffer; - s >> buffer; - - if (buffer != cachedStrings.at(i)) { - cachedStrings[i] = buffer; - } - - fields.append(Field(cachedStrings.at(i))); - } else if (uds & KIO::UDSEntry::UDS_NUMBER) { - long long value; - s >> value; - fields.append(Field(value)); - } else { - Q_ASSERT_X(false, "KIO::UDSEntry", "Found a field with an invalid type"); - } - } + d->replace(field, value); } -void debugUDSEntry(QDebug stream, const KIO::UDSEntry &entry) +void UDSEntry::replace(uint field, long long value) { - 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; - } else { - Q_ASSERT_X(false, "KIO::UDSEntry", "Found a field with an invalid type"); - } - } - stream << " ]"; + d->replace(field, value); }