summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVolker Hilsheimer <volker.hilsheimer@qt.io>2025-12-04 20:19:57 +0100
committerVolker Hilsheimer <volker.hilsheimer@qt.io>2025-12-05 18:10:05 +0100
commit93fb8b0db67639495e345c70aa80a74fd579180a (patch)
tree967e1d0f4baebbac7127bef1b03e15f9794305e9
parent9f9d282af984baa5e2bf0b699a7c8e3d4a8a6fbe (diff)
QRM: implement itemData in terms of multiData
No need to duplicate the entire logic. The only overhead is that we have to create a QModelRoleDataSpan for all roles, except our internal roles. Using a QVarLengthArray makes that cheap. The only special case we keep is for items that are backed by a type that is directly convertible to a QMap<int, QVariant>. This comes with a small overhead for acessing the element at runtime. Pick-to: 6.10 Change-Id: I33f86d231bef9036a7e83584d1bf013f129b8075 Reviewed-by: Artem Dyomin <artem.dyomin@qt.io>
-rw-r--r--src/corelib/itemmodels/qrangemodel_impl.h84
1 files changed, 23 insertions, 61 deletions
diff --git a/src/corelib/itemmodels/qrangemodel_impl.h b/src/corelib/itemmodels/qrangemodel_impl.h
index 544e66d2211..0233727f848 100644
--- a/src/corelib/itemmodels/qrangemodel_impl.h
+++ b/src/corelib/itemmodels/qrangemodel_impl.h
@@ -23,6 +23,7 @@
#include <QtCore/qmap.h>
#include <QtCore/qscopedvaluerollback.h>
#include <QtCore/qset.h>
+#include <QtCore/qvarlengtharray.h>
#include <algorithm>
#include <functional>
@@ -1217,73 +1218,34 @@ public:
QMap<int, QVariant> itemData(const QModelIndex &index) const
{
QMap<int, QVariant> result;
- bool tried = false;
- const auto readItemData = [this, &index, &result, &tried](const auto &value){
- Q_UNUSED(this);
- Q_UNUSED(index);
- using value_type = q20::remove_cvref_t<decltype(value)>;
- using multi_role = QRangeModelDetails::is_multi_role<value_type>;
- using wrapped_value_type = QRangeModelDetails::wrapped_t<value_type>;
- if constexpr (QRangeModelDetails::item_access<wrapped_value_type>()) {
- using ItemAccess = QRangeModelDetails::QRangeModelItemAccess<wrapped_value_type>;
- tried = true;
+ if (index.isValid()) {
+ bool tried = false;
+
+ // optimisation for items backed by a QMap<int, QVariant> or equivalent
+ readAt(index, [&result, &tried](const auto &value) {
+ if constexpr (std::is_convertible_v<decltype(value), decltype(result)>) {
+ tried = true;
+ result = value;
+ }
+ });
+ if (!tried) {
const auto roles = this->itemModel().roleNames().keys();
- for (auto &role : roles) {
+ QVarLengthArray<QModelRoleData, 16> roleDataArray;
+ roleDataArray.reserve(roles.size());
+ for (auto role : roles) {
if (isRangeModelRole(role))
continue;
- QVariant data = ItemAccess::readRole(value, role);
- if (data.isValid())
- result[role] = std::move(data);
+ roleDataArray.emplace_back(role);
}
- } else if constexpr (multi_role()) {
- tried = true;
- if constexpr (std::is_convertible_v<value_type, decltype(result)>) {
- result = value;
- } else {
- const auto roleNames = [this]() -> QHash<int, QByteArray> {
- Q_UNUSED(this);
- if constexpr (!multi_role::int_key)
- return this->itemModel().roleNames();
- else
- return {};
- }();
- for (auto it = std::begin(value); it != std::end(value); ++it) {
- const int role = [&roleNames, key = QRangeModelDetails::key(it)]() {
- Q_UNUSED(roleNames);
- if constexpr (multi_role::int_key)
- return int(key);
- else
- return roleNames.key(key.toUtf8(), -1);
- }();
-
- if (role != -1 && role != Qt::RangeModelDataRole && role != Qt::RangeModelAdapterRole)
- result.insert(role, QRangeModelDetails::value(it));
- }
- }
- } else if constexpr (has_metaobject<value_type>) {
- if (row_traits::fixed_size() <= 1) {
- tried = true;
- const auto roleNames = this->itemModel().roleNames();
- const auto end = roleNames.keyEnd();
- for (auto it = roleNames.keyBegin(); it != end; ++it) {
- const int role = *it;
- if (isRangeModelRole(role))
- continue;
- QVariant data = readRole(index, role, QRangeModelDetails::pointerTo(value));
- if (data.isValid())
- result[role] = std::move(data);
- }
- }
- }
- };
-
- if (index.isValid()) {
- readAt(index, readItemData);
+ QModelRoleDataSpan roleDataSpan(roleDataArray);
+ multiData(index, roleDataSpan);
- if (!tried) { // no multi-role item found
- result = this->itemModel().QAbstractItemModel::itemData(index);
- result.remove(Qt::RangeModelAdapterRole);
+ for (auto &&roleData : std::move(roleDataSpan)) {
+ QVariant data = roleData.data();
+ if (data.isValid())
+ result[roleData.role()] = std::move(data);
+ }
}
}
return result;