我如何*直接*附加到存储在 QVariantMap 中的 QVariantList?
How can I *directly* append to a QVariantList, stored in a QVariantMap?
我有一个 QVariantMaps 集合,其中一些条目包含 QVariantLists。
我需要追加到列表中。这些列表可能会变得相当大,我必须对其中的许多列表执行此操作,每秒多次,基本上整个程序都是 运行。所以,效率在这里非常重要..
虽然我没有找到避免复制这些列表的方法!它们也可能是不可变的。 :(
这个有效:
map[ key ] = QVariantList() << map[ key ].toList() << someOtherVarList;
但是,这(在引擎盖下)做的工作比我想要的要多得多...
这是我试过的东西,但是 运行 撞墙了:
我可以通过使用我使用 QMutableMapIterator
:
编写的这个宏来获得指向我想直接修改的变体的非常量指针
#define getMapValuePtr( keyType, valueType, map, keyValue, ptrName ) \
valueType *ptrName( nullptr ); \
for( QMap<keyType, valueType>::iterator it = map.begin(); \
it != map.end(); ++it ) \
{ if( it.key()==keyValue ) { ptrName = &(*it); break; } }
示例:
const QString key( "mylist" );
QVariantMap map;
map[ key ] = QVariantList( {"a","b","c"} );
getMapValuePtr( QString, QVariant, map, key, valuePtr )
所以现在 valuePtr
可以让我直接修改地图中的值,但它是一个 QVariant 的事实仍然存在...
我接下来尝试了以下操作,但 Qt Creator 没有突出显示任何内容以指示错误,但尽管如此,它还是无法完全编译...
QVariantList *valListPtr( qvariant_cast<QVariantList *>(*valuePtr) );
valListPtr->append( QVariantList( {"x","y","z"} ) );
想法?
注意:并非这些地图中的所有条目都是列表。因此我不能将我的地图类型更改为 QMap<QString,QVariantList>
。我试过了,许多客户 类 都对这段代码感到满意……如果它起作用的话,通过隐含地消除这个最后的症结点,这会简化事情。
知道了!
我在正确的轨道上,但必须深入研究 Qt 源代码才能弄清楚如何完成它。我现在有另一个宏可以调用,它将带我完成剩下的工作:
#define varPtrToListPtr( varPtr, ptrName ) \
QVariantList *ptrName( varPtr->type() == QVariant::List ? \
static_cast<QVariantList *>( static_cast<void *>( &(varPtr->d.data.c) ) ) \
: nullptr );
因此,这是上面的示例,并填充了故事的其余部分:
const QString key( "mylist" );
QVariantMap map;
map[ key ] = QVariantList( {"a","b","c"} );
getMapValuePtr( QString, QVariant, map, key, valuePtr )
if( !valuePtr ) return; // imagine this being inside a function...
varPtrToListPtr( valuePtr, valueListPtr )
if( valueListPtr ) *valueListPtr << QVariantList( {"x","y","z"} );
这实现了与我在问题中展示的直接 one-liner 相同的结果,但现在我避免了创建和销毁巨型列表的临时副本的所有开销!
诚然,与使用 QMap::value( key )
相比,使用迭代器进行初始搜索可能会耗费一些时间,但是我这里的 none 地图有很多 k/v 对,因此总体收益避免列表副本否定了这一点。
更新:
我 运行 使用此方法与原始方法进行了一些测试,并观察到它确实节省了相同工作负载所需时间的 99% 以上。就像在 50 毫秒内完成一项任务,而不是旧方法所需要的痛苦的 7.5 秒。
这最初是在 Windows 上针对 MSVC 编写的。然而,我发现,在其他 platforms/compilers 上,除非您对 Qt 基础库进行 1 行调整,否则无法构建:
- 打开 class QVariant 的 Qt 头文件。
- 在文件中搜索包含以下内容的行:
Private d;
- 在其正上方添加行:
public: // HACK!
。这使其他构建上下文与对该 class 成员的 MSVC 访问保持一致。
Note: I fully acknowledge the "bad form", and the downsides, to this solution... BUT the payoff may be worth it for you. It was for my use case.
I have a collection of QVariantMaps which contains QVariantLists in SOME of their entries.
I need to append to the lists.
不要。显然你对这些 QVariant
s 有一些模式,否则你不会知道它们是否是一个列表。您是否针对它的强类型模型进行操作,然后在最后一刻将其转换为 QVariant
(或其他)
map[ key ] = QVariantList() << map[ key ].toList() << someOtherVarList;
这就是将每个元素至少复制 两次 ,并查找变体两次,因此您可以通过将其拖放到
来立即削减 50%
auto & var = map[ key ];
var = (var.toList() << someOtherVarList);
主要问题是 QVariant
对性能来说是垃圾。对比 std::any
可以让您对存储的值进行引用访问。
我有一个 QVariantMaps 集合,其中一些条目包含 QVariantLists。
我需要追加到列表中。这些列表可能会变得相当大,我必须对其中的许多列表执行此操作,每秒多次,基本上整个程序都是 运行。所以,效率在这里非常重要..
虽然我没有找到避免复制这些列表的方法!它们也可能是不可变的。 :(
这个有效:
map[ key ] = QVariantList() << map[ key ].toList() << someOtherVarList;
但是,这(在引擎盖下)做的工作比我想要的要多得多...
这是我试过的东西,但是 运行 撞墙了:
我可以通过使用我使用 QMutableMapIterator
:
#define getMapValuePtr( keyType, valueType, map, keyValue, ptrName ) \
valueType *ptrName( nullptr ); \
for( QMap<keyType, valueType>::iterator it = map.begin(); \
it != map.end(); ++it ) \
{ if( it.key()==keyValue ) { ptrName = &(*it); break; } }
示例:
const QString key( "mylist" );
QVariantMap map;
map[ key ] = QVariantList( {"a","b","c"} );
getMapValuePtr( QString, QVariant, map, key, valuePtr )
所以现在 valuePtr
可以让我直接修改地图中的值,但它是一个 QVariant 的事实仍然存在...
我接下来尝试了以下操作,但 Qt Creator 没有突出显示任何内容以指示错误,但尽管如此,它还是无法完全编译...
QVariantList *valListPtr( qvariant_cast<QVariantList *>(*valuePtr) );
valListPtr->append( QVariantList( {"x","y","z"} ) );
想法?
注意:并非这些地图中的所有条目都是列表。因此我不能将我的地图类型更改为 QMap<QString,QVariantList>
。我试过了,许多客户 类 都对这段代码感到满意……如果它起作用的话,通过隐含地消除这个最后的症结点,这会简化事情。
知道了!
我在正确的轨道上,但必须深入研究 Qt 源代码才能弄清楚如何完成它。我现在有另一个宏可以调用,它将带我完成剩下的工作:
#define varPtrToListPtr( varPtr, ptrName ) \
QVariantList *ptrName( varPtr->type() == QVariant::List ? \
static_cast<QVariantList *>( static_cast<void *>( &(varPtr->d.data.c) ) ) \
: nullptr );
因此,这是上面的示例,并填充了故事的其余部分:
const QString key( "mylist" );
QVariantMap map;
map[ key ] = QVariantList( {"a","b","c"} );
getMapValuePtr( QString, QVariant, map, key, valuePtr )
if( !valuePtr ) return; // imagine this being inside a function...
varPtrToListPtr( valuePtr, valueListPtr )
if( valueListPtr ) *valueListPtr << QVariantList( {"x","y","z"} );
这实现了与我在问题中展示的直接 one-liner 相同的结果,但现在我避免了创建和销毁巨型列表的临时副本的所有开销!
诚然,与使用 QMap::value( key )
相比,使用迭代器进行初始搜索可能会耗费一些时间,但是我这里的 none 地图有很多 k/v 对,因此总体收益避免列表副本否定了这一点。
更新:
我 运行 使用此方法与原始方法进行了一些测试,并观察到它确实节省了相同工作负载所需时间的 99% 以上。就像在 50 毫秒内完成一项任务,而不是旧方法所需要的痛苦的 7.5 秒。
这最初是在 Windows 上针对 MSVC 编写的。然而,我发现,在其他 platforms/compilers 上,除非您对 Qt 基础库进行 1 行调整,否则无法构建:
- 打开 class QVariant 的 Qt 头文件。
- 在文件中搜索包含以下内容的行:
Private d;
- 在其正上方添加行:
public: // HACK!
。这使其他构建上下文与对该 class 成员的 MSVC 访问保持一致。
Note: I fully acknowledge the "bad form", and the downsides, to this solution... BUT the payoff may be worth it for you. It was for my use case.
I have a collection of QVariantMaps which contains QVariantLists in SOME of their entries.
I need to append to the lists.
不要。显然你对这些 QVariant
s 有一些模式,否则你不会知道它们是否是一个列表。您是否针对它的强类型模型进行操作,然后在最后一刻将其转换为 QVariant
(或其他)
map[ key ] = QVariantList() << map[ key ].toList() << someOtherVarList;
这就是将每个元素至少复制 两次 ,并查找变体两次,因此您可以通过将其拖放到
来立即削减 50%auto & var = map[ key ];
var = (var.toList() << someOtherVarList);
主要问题是 QVariant
对性能来说是垃圾。对比 std::any
可以让您对存储的值进行引用访问。