From 6d9ec41f6fef7af0129d13fc99fffc7a548f6125 Mon Sep 17 00:00:00 2001 From: Giuseppe D'Angelo Date: Mon, 3 Aug 2020 23:40:25 +0200 Subject: [PATCH] Mac: (temporarily?) drop support for QMultiMap in QSettings In preparation for the QMap/QMultiMap split. The previous code had a workaround for storing multimaps, because the CF classes actually don't support it: build a dictionary from one key to a _list_ of values. Stop doing that. In principle, if QMultiMap support does get added to QVariant (which it probably should), then a similar workaround could be readded for QMultiMap support. [ChangeLog][Important Behavior Changes][QSettings] On Apple platforms, when using the native format, QSettings is no longer able to handle QVariantMap values which are actually multimaps. Since the native storage does not actually support multimaps, QSettings used to flatten and unflatten the maps. However, with QMap being changed to no longer allow for equivalent keys, flattening when writing does not make sense any more (there cannot be equivalent keys, because QMap in Qt 6 is a single-key map). Reading existing settings is supported by having a key in the map mapping to a QVariantList of values. Support for QMultiMap may be added back to QVariant and QSettings in a future version of Qt. Change-Id: Iaa9535100fe5ef55693f22a2068454a84180b4a6 Reviewed-by: Thiago Macieira --- src/corelib/io/qsettings_mac.cpp | 62 ++++++++++---------------------- 1 file changed, 19 insertions(+), 43 deletions(-) diff --git a/src/corelib/io/qsettings_mac.cpp b/src/corelib/io/qsettings_mac.cpp index a2b943f9ec8..70a2fe49e5a 100644 --- a/src/corelib/io/qsettings_mac.cpp +++ b/src/corelib/io/qsettings_mac.cpp @@ -122,52 +122,25 @@ static QCFType macValue(const QVariant &value) break; case QVariant::Map: { - /* - QMap is potentially a multimap, - whereas CFDictionary is a single-valued map. To allow - for multiple values with the same key, we store - multiple values in a CFArray. To avoid ambiguities, - we also wrap lists in a CFArray singleton. - */ - QMap map = value.toMap(); - QMap::const_iterator i = map.constBegin(); + const QVariantMap &map = value.toMap(); + const int mapSize = map.size(); - int maxUniqueKeys = map.size(); - int numUniqueKeys = 0; - QVarLengthArray > cfkeys(maxUniqueKeys); - QVarLengthArray > cfvalues(maxUniqueKeys); + QVarLengthArray> cfkeys; + cfkeys.reserve(mapSize); + std::transform(map.keyBegin(), map.keyEnd(), + std::back_inserter(cfkeys), + [](const auto &key) { return key.toCFString(); }); - while (i != map.constEnd()) { - const QString &key = i.key(); - QList values; - - do { - values << i.value(); - ++i; - } while (i != map.constEnd() && i.key() == key); - - bool singleton = (values.count() == 1); - if (singleton) { - switch (values.constFirst().type()) { - // should be same as above (look for LIST) - case QVariant::List: - case QVariant::StringList: - case QVariant::Polygon: - singleton = false; - default: - ; - } - } - - cfkeys[numUniqueKeys] = key.toCFString(); - cfvalues[numUniqueKeys] = singleton ? macValue(values.constFirst()) : macList(values); - ++numUniqueKeys; - } + QVarLengthArray> cfvalues; + cfvalues.reserve(mapSize); + std::transform(map.begin(), map.end(), + std::back_inserter(cfvalues), + [](const auto &value) { return macValue(value); }); result = CFDictionaryCreate(kCFAllocatorDefault, reinterpret_cast(cfkeys.data()), reinterpret_cast(cfvalues.data()), - CFIndex(numUniqueKeys), + CFIndex(mapSize), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); } @@ -283,15 +256,18 @@ static QVariant qtValue(CFPropertyListRef cfvalue) QVarLengthArray values(size); CFDictionaryGetKeysAndValues(cfdict, keys.data(), values.data()); - QMultiMap map; + QVariantMap map; for (int i = 0; i < size; ++i) { QString key = QString::fromCFString(static_cast(keys[i])); if (CFGetTypeID(values[i]) == arrayTypeId) { CFArrayRef cfarray = static_cast(values[i]); CFIndex arraySize = CFArrayGetCount(cfarray); - for (CFIndex j = arraySize - 1; j >= 0; --j) - map.insert(key, qtValue(CFArrayGetValueAtIndex(cfarray, j))); + QVariantList list; + list.reserve(arraySize); + for (CFIndex j = 0; j < arraySize; ++j) + list.append(qtValue(CFArrayGetValueAtIndex(cfarray, j))); + map.insert(key, list); } else { map.insert(key, qtValue(values[i])); }