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 <thiago.macieira@intel.com>
This commit is contained in:
Giuseppe D'Angelo 2020-08-03 23:40:25 +02:00 committed by Tor Arne Vestbø
parent 76068d0114
commit 6d9ec41f6f

View File

@ -122,52 +122,25 @@ static QCFType<CFPropertyListRef> macValue(const QVariant &value)
break;
case QVariant::Map:
{
/*
QMap<QString, QVariant> 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<QString, QVariant> map = value.toMap();
QMap<QString, QVariant>::const_iterator i = map.constBegin();
const QVariantMap &map = value.toMap();
const int mapSize = map.size();
int maxUniqueKeys = map.size();
int numUniqueKeys = 0;
QVarLengthArray<QCFType<CFPropertyListRef> > cfkeys(maxUniqueKeys);
QVarLengthArray<QCFType<CFPropertyListRef> > cfvalues(maxUniqueKeys);
QVarLengthArray<QCFType<CFPropertyListRef>> 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<QVariant> 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<QCFType<CFPropertyListRef>> 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<const void **>(cfkeys.data()),
reinterpret_cast<const void **>(cfvalues.data()),
CFIndex(numUniqueKeys),
CFIndex(mapSize),
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
}
@ -283,15 +256,18 @@ static QVariant qtValue(CFPropertyListRef cfvalue)
QVarLengthArray<CFPropertyListRef> values(size);
CFDictionaryGetKeysAndValues(cfdict, keys.data(), values.data());
QMultiMap<QString, QVariant> map;
QVariantMap map;
for (int i = 0; i < size; ++i) {
QString key = QString::fromCFString(static_cast<CFStringRef>(keys[i]));
if (CFGetTypeID(values[i]) == arrayTypeId) {
CFArrayRef cfarray = static_cast<CFArrayRef>(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]));
}