用非基元填充 CapnProto 列表

Fill CapnProto List with non-primitive

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

For List where Foo is a non-primitive type, the type returned by operator[] and iterator::operator*() is Foo::Reader (for List::Reader) or Foo::Builder (for List::Builder). The builder’s set method takes a Foo::Reader as its second parameter.

虽然使用 "set" 似乎适用于非原始类型:

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

有一个"set"方法,但是叫setWithCaveats():

destListBuilder.setWithCaveats(index, sourceStructReader)

这是为了让您知道在设置结构列表的元素时存在一些难以理解的问题。问题源于这样一个事实,即结构列表 不是 表示为您可能期望的指针列表,而是它们是一系列 "flattened" 连续结构,所有相同的大小。这意味着列表中所有结构的 space 是在您初始化列表时分配的。因此,当您调用 setWithCaveats() 时,目标 space 之前已分配,并且您正在将源结构复制到 space.

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

当然,可能是在您的应用程序中,您知道结构值不是来自较新版本,或者您不关心是否丢失了您不知道的字段。在这种情况下,setWithCaveats() 将执行您想要的操作。

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

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