使用非基元填充CapnProto列表

时间:2018-03-19 22:53:35

标签: c++ capnproto

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

  

对于Foo是非基本类型的List,返回的类型   operator []和iterator :: operator *()是Foo :: Reader(for   List :: Reader)或Foo :: Builder(用于List :: Builder)。该   builder的set方法将Foo :: Reader作为其第二个参数。

虽然使用“set”似乎适用于非原始类型: Other stack overflow question for primitives only

对于自动生成的非基元列表,似乎没有“设置”功能。我的CapnProto生成是否以某种方式失败,或者是否存在另一种在非基元列表中设置元素的方法?

1 个答案:

答案 0 :(得分:1)

有一个“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));