用非基元填充 CapnProto 列表

Fill CapnProto List with non-primitive

本文关键字:CapnProto 列表 填充      更新时间:2023-10-16

根据CapnProto文档:(注意:我使用的是C++版本)

对于 Foo 是非基元类型的列表,返回的类型由 运算符[]和迭代器::operator*()是Foo::Reader(用于 List::Reader) 或 Foo::Builder(对于 List::Builder)。这 builder 的 set 方法采用 Foo::Reader 作为其第二个参数。

虽然使用"set"似乎适用于非基元类型: 仅适用于原语的其他堆栈溢出问题

对于自动生成的非原语列表,似乎没有"set"函数。我的 CapnProto 生成是否以某种方式失败,或者是否有另一种方法可以在非原语列表中设置元素?

有一个"set"方法,但它被称为setWithCaveats()

destListBuilder.setWithCaveats(index, sourceStructReader)

这是为了让你知道在设置结构列表的元素时存在一些模糊的问题。问题源于这样一个事实,即结构列表并没有像您期望的那样表示为指针列表,而是一系列"扁平化"的连续结构,所有结构的大小都相同。这意味着在初始化列表时会为列表中所有结构分配空间。因此,当您调用setWithCaveats()时,目标空间之前已经分配,并且您正在将源结构复制到该空间中。

面对不同的版本,这会带来一个问题:源结构可能是使用较新版本的协议构建的,其中定义了其他字段。在这种情况下,它实际上可能比预期的要大。但是,目标空间已经根据您编译的协议版本进行了分配。所以,它太小了!不幸的是,别无选择,只能丢弃我们不知道的新定义字段。因此,数据可能会丢失。

当然,可能是在您的应用程序中,您知道结构值不是来自较新版本,或者您不在乎是否丢失了您不知道的字段。在这种情况下,setWithCaveats()会做你想做的事。

如果要小心保留未知字段,则可能需要查看方法capnp::Orphanage::newOrphanConcat()。此方法可以将结构读取器列表的列表连接成单个列表,这样就不会丢失任何数据 - 目标列表分配的每个结构的大小等于所有输入结构的最大值。

auto orphanage = Orphanage::getForMessageContaining(builder);
auto orphan = orphanage.newOrphanConcat({list1Reader, list2Reader});
builder.adoptListField(kj::mv(orphan));